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:
authorAntonioya <blendergit@gmail.com>2018-07-31 11:22:19 +0300
committerAntonioya <blendergit@gmail.com>2018-07-31 11:50:43 +0300
commit66da2f537ae80ce2b31d1eaf34ad8c03d858938d (patch)
tree4776b9d2e43e4280d01d6f0b7088e6d4f417db0f /source
parent27496cc46bbfd76e98ad3b1ccb8fea534763ffb5 (diff)
New Grease Pencil object for 2D animation
This commit merge the full development done in greasepencil-object branch and include mainly the following features. - New grease pencil object. - New drawing engine. - New grease pencil modes Draw/Sculpt/Edit and Weight Paint. - New brushes for grease pencil. - New modifiers for grease pencil. - New shaders FX. - New material system (replace old palettes and colors). - Split of annotations (old grease pencil) and new grease pencil object. - UI adapted to blender 2.8. You can get more info here: https://code.blender.org/2017/12/drawing-2d-animation-in-blender-2-8/ https://code.blender.org/2018/07/grease-pencil-status-update/ This is the result of nearly two years of development and I want thanks firstly the other members of the grease pencil team: Daniel M. Lara, Matias Mendiola and Joshua Leung for their support, ideas and to keep working in the project all the time, without them this project had been impossible. Also, I want thanks other Blender developers for their help, advices and to be there always to help me, and specially to Clément Foucault, Dalai Felinto, Pablo Vázquez and Campbell Barton.
Diffstat (limited to 'source')
-rw-r--r--source/blender/CMakeLists.txt4
-rw-r--r--source/blender/blenkernel/BKE_brush.h8
-rw-r--r--source/blender/blenkernel/BKE_context.h12
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h103
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h256
-rw-r--r--source/blender/blenkernel/BKE_icons.h7
-rw-r--r--source/blender/blenkernel/BKE_lattice.h1
-rw-r--r--source/blender/blenkernel/BKE_material.h4
-rw-r--r--source/blender/blenkernel/BKE_object.h12
-rw-r--r--source/blender/blenkernel/BKE_paint.h3
-rw-r--r--source/blender/blenkernel/BKE_shader_fx.h180
-rw-r--r--source/blender/blenkernel/CMakeLists.txt6
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c7
-rw-r--r--source/blender/blenkernel/intern/brush.c380
-rw-r--r--source/blender/blenkernel/intern/colortools.c19
-rw-r--r--source/blender/blenkernel/intern/context.c20
-rw-r--r--source/blender/blenkernel/intern/deform.c4
-rw-r--r--source/blender/blenkernel/intern/gpencil.c1383
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c679
-rw-r--r--source/blender/blenkernel/intern/icons.c44
-rw-r--r--source/blender/blenkernel/intern/library.c1
-rw-r--r--source/blender/blenkernel/intern/library_query.c25
-rw-r--r--source/blender/blenkernel/intern/material.c76
-rw-r--r--source/blender/blenkernel/intern/object.c194
-rw-r--r--source/blender/blenkernel/intern/object_deform.c16
-rw-r--r--source/blender/blenkernel/intern/object_update.c4
-rw-r--r--source/blender/blenkernel/intern/paint.c13
-rw-r--r--source/blender/blenkernel/intern/scene.c81
-rw-r--r--source/blender/blenkernel/intern/shader_fx.c245
-rw-r--r--source/blender/blenlib/BLI_math_vector.h3
-rw-r--r--source/blender/blenlib/BLI_rand.h3
-rw-r--r--source/blender/blenlib/intern/listbase.c3
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c13
-rw-r--r--source/blender/blenlib/intern/rand.c12
-rw-r--r--source/blender/blenloader/intern/readfile.c246
-rw-r--r--source/blender/blenloader/intern/versioning_260.c4
-rw-r--r--source/blender/blenloader/intern/versioning_270.c85
-rw-r--r--source/blender/blenloader/intern/versioning_280.c199
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c50
-rw-r--r--source/blender/blenloader/intern/writefile.c105
-rw-r--r--source/blender/collada/SceneExporter.cpp2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc34
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc124
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc9
-rw-r--r--source/blender/draw/CMakeLists.txt34
-rw-r--r--source/blender/draw/DRW_engine.h3
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c296
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c739
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c1336
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c794
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h355
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c353
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader_fx.c848
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl60
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl86
-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_light_frag.glsl70
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl50
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl64
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl101
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl70
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl40
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl12
-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.glsl48
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl15
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl140
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl14
-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.glsl49
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl82
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl37
-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.glsl46
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl208
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl37
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl45
-rw-r--r--source/blender/draw/intern/DRW_render.h1
-rw-r--r--source/blender/draw/intern/draw_cache.c60
-rw-r--r--source/blender/draw/intern/draw_cache.h3
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h4
-rw-r--r--source/blender/draw/intern/draw_manager.c145
-rw-r--r--source/blender/draw/modes/draw_mode_engines.h1
-rw-r--r--source/blender/draw/modes/object_mode.c18
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c15
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c3
-rw-r--r--source/blender/editors/animation/anim_deps.c10
-rw-r--r--source/blender/editors/animation/anim_draw.c4
-rw-r--r--source/blender/editors/animation/anim_filter.c13
-rw-r--r--source/blender/editors/animation/keyframes_draw.c9
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt52
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt6
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c1065
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c2382
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c989
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_add_monkey.c1567
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c695
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c70
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c1809
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c1635
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c1246
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h271
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c71
-rw-r--r--source/blender/editors/gpencil/gpencil_old.c219
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c547
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c1337
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c712
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c293
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c1262
-rw-r--r--source/blender/editors/include/ED_anim_api.h5
-rw-r--r--source/blender/editors/include/ED_datafiles.h63
-rw-r--r--source/blender/editors/include/ED_gpencil.h188
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h5
-rw-r--r--source/blender/editors/include/ED_object.h35
-rw-r--r--source/blender/editors/include/UI_icons.h24
-rw-r--r--source/blender/editors/include/UI_interface.h9
-rw-r--r--source/blender/editors/interface/interface_icons.c100
-rw-r--r--source/blender/editors/interface/interface_layout.c8
-rw-r--r--source/blender/editors/interface/interface_templates.c308
-rw-r--r--source/blender/editors/interface/resources.c20
-rw-r--r--source/blender/editors/object/CMakeLists.txt4
-rw-r--r--source/blender/editors/object/object_add.c131
-rw-r--r--source/blender/editors/object/object_edit.c42
-rw-r--r--source/blender/editors/object/object_gpencil_modifier.c637
-rw-r--r--source/blender/editors/object/object_intern.h15
-rw-r--r--source/blender/editors/object/object_modes.c18
-rw-r--r--source/blender/editors/object/object_modifier.c238
-rw-r--r--source/blender/editors/object/object_ops.c15
-rw-r--r--source/blender/editors/object/object_relations.c23
-rw-r--r--source/blender/editors/object/object_select.c5
-rw-r--r--source/blender/editors/object/object_shader_fx.c469
-rw-r--r--source/blender/editors/object/object_transform.c103
-rw-r--r--source/blender/editors/render/render_opengl.c94
-rw-r--r--source/blender/editors/render/render_preview.c38
-rw-r--r--source/blender/editors/render/render_shading.c8
-rw-r--r--source/blender/editors/screen/area.c28
-rw-r--r--source/blender/editors/screen/screen_context.c84
-rw-r--r--source/blender/editors/screen/screen_ops.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c46
-rw-r--r--source/blender/editors/space_action/action_select.c69
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c44
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c17
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c41
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c2
-rw-r--r--source/blender/editors/space_clip/space_clip.c6
-rw-r--r--source/blender/editors/space_image/image_buttons.c2
-rw-r--r--source/blender/editors/space_info/info_stats.c32
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c3
-rw-r--r--source/blender/editors/space_nla/nla_channels.c1
-rw-r--r--source/blender/editors/space_node/drawnode.c30
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c415
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c30
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c2
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c4
-rw-r--r--source/blender/editors/space_view3d/drawobject.c1
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c13
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c33
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c33
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c24
-rw-r--r--source/blender/editors/transform/transform.c69
-rw-r--r--source/blender/editors/transform/transform_conversions.c330
-rw-r--r--source/blender/editors/transform/transform_generics.c22
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c9
-rw-r--r--source/blender/editors/transform/transform_snap_object.c7
-rw-r--r--source/blender/editors/undo/ed_undo.c27
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt70
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h53
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c142
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h47
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c558
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c178
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c355
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c360
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c213
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c239
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c285
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c143
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c171
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c123
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c152
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c193
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c171
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c186
-rw-r--r--source/blender/gpu/CMakeLists.txt8
-rw-r--r--source/blender/gpu/GPU_shader.h5
-rw-r--r--source/blender/gpu/intern/gpu_shader.c14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl166
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_fill_vert.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl20
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl196
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl33
-rw-r--r--source/blender/makesdna/DNA_ID.h2
-rw-r--r--source/blender/makesdna/DNA_brush_types.h109
-rw-r--r--source/blender/makesdna/DNA_color_types.h1
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h404
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h319
-rw-r--r--source/blender/makesdna/DNA_material_types.h76
-rw-r--r--source/blender/makesdna/DNA_object_enums.h5
-rw-r--r--source/blender/makesdna/DNA_object_types.h19
-rw-r--r--source/blender/makesdna/DNA_scene_types.h105
-rw-r--r--source/blender/makesdna/DNA_shader_fx_types.h196
-rw-r--r--source/blender/makesdna/DNA_space_types.h3
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h6
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h29
-rw-r--r--source/blender/makesdna/intern/makesdna.c4
-rw-r--r--source/blender/makesrna/RNA_access.h28
-rw-r--r--source/blender/makesrna/RNA_enum_types.h4
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt2
-rw-r--r--source/blender/makesrna/intern/makesrna.c2
-rw-r--r--source/blender/makesrna/intern/rna_brush.c441
-rw-r--r--source/blender/makesrna/intern/rna_context.c4
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c1003
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c1314
-rw-r--r--source/blender/makesrna/intern/rna_internal.h7
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c13
-rw-r--r--source/blender/makesrna/intern/rna_material.c337
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c1
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c1
-rw-r--r--source/blender/makesrna/intern/rna_object.c212
-rw-r--r--source/blender/makesrna/intern/rna_palette.c4
-rw-r--r--source/blender/makesrna/intern/rna_scene.c425
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c149
-rw-r--r--source/blender/makesrna/intern/rna_shader_fx.c538
-rw-r--r--source/blender/makesrna/intern/rna_space.c151
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c1
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c26
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c8
-rw-r--r--source/blender/render/intern/source/external_engine.c3
-rw-r--r--source/blender/shader_fx/CMakeLists.txt64
-rw-r--r--source/blender/shader_fx/FX_shader_types.h47
-rw-r--r--source/blender/shader_fx/intern/FX_shader_blur.c66
-rw-r--r--source/blender/shader_fx/intern/FX_shader_colorize.c69
-rw-r--r--source/blender/shader_fx/intern/FX_shader_flip.c69
-rw-r--r--source/blender/shader_fx/intern/FX_shader_light.c104
-rw-r--r--source/blender/shader_fx/intern/FX_shader_pixel.c66
-rw-r--r--source/blender/shader_fx/intern/FX_shader_rim.c70
-rw-r--r--source/blender/shader_fx/intern/FX_shader_swirl.c103
-rw-r--r--source/blender/shader_fx/intern/FX_shader_util.c56
-rw-r--r--source/blender/shader_fx/intern/FX_shader_util.h36
-rw-r--r--source/blender/shader_fx/intern/FX_shader_wave.c71
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c2
-rw-r--r--source/creator/creator.c4
249 files changed, 36614 insertions, 5624 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 5709ac723f4..2c9b1efe2f4 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -44,7 +44,9 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fileglobal_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_freestyle_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_genfile.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_shader_fx_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpu_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_group_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_types.h
@@ -112,6 +114,8 @@ add_subdirectory(gpu)
add_subdirectory(imbuf)
add_subdirectory(nodes)
add_subdirectory(modifiers)
+add_subdirectory(gpencil_modifiers)
+add_subdirectory(shader_fx)
add_subdirectory(makesdna)
add_subdirectory(makesrna)
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index eda1c51bbc2..489746cbfd9 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -28,11 +28,14 @@
*/
enum eCurveMappingPreset;
+struct bContext;
struct Brush;
+struct Paint;
struct ImBuf;
struct ImagePool;
struct Main;
struct Scene;
+struct ToolSettings;
struct UnifiedPaintSettings;
// enum eCurveMappingPreset;
@@ -45,14 +48,17 @@ void BKE_brush_system_exit(void);
/* datablock functions */
void BKE_brush_init(struct Brush *brush);
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_first_search(struct Main *bmain, const eObjectMode ob_mode);
void BKE_brush_copy_data(struct Main *bmain, struct Brush *brush_dst, const struct Brush *brush_src, const int flag);
struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush);
void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool lib_local);
-void BKE_brush_unlink(struct Main *bmain, struct Brush *brush);
void BKE_brush_free(struct Brush *brush);
void BKE_brush_sculpt_reset(struct Brush *brush);
+void BKE_brush_gpencil_presets(struct bContext *C);
+struct Brush *BKE_brush_getactive_gpencil(struct ToolSettings *ts);
+struct Paint *BKE_brush_get_gpencil_paint(struct ToolSettings *ts);
/* 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 9f57859d318..28dcf9cb127 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -65,9 +65,7 @@ struct bPoseChannel;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
-struct bGPDpalette;
-struct bGPDpalettecolor;
-struct bGPDbrush;
+struct Brush;
struct wmWindow;
struct wmWindowManager;
struct RenderEngineType;
@@ -120,6 +118,10 @@ enum {
CTX_MODE_PAINT_TEXTURE,
CTX_MODE_PARTICLE,
CTX_MODE_OBJECT,
+ CTX_MODE_GPENCIL_PAINT,
+ CTX_MODE_GPENCIL_EDIT,
+ CTX_MODE_GPENCIL_SCULPT,
+ CTX_MODE_GPENCIL_WEIGHT,
CTX_MODE_NUM /* must be last */
};
@@ -313,9 +315,7 @@ int CTX_data_visible_pose_bones(const bContext *C, ListBase *list);
struct bGPdata *CTX_data_gpencil_data(const bContext *C);
struct bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C);
struct bGPDframe *CTX_data_active_gpencil_frame(const bContext *C);
-struct bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C);
-struct bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C);
-struct bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C);
+struct Brush *CTX_data_active_gpencil_brush(const bContext *C);
int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list);
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 3a951b7860d..887a7f4f67b 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -31,25 +31,45 @@
* \author Joshua Leung
*/
+struct CurveMapping;
+struct Depsgraph;
+struct GpencilModifierData;
struct ToolSettings;
struct ListBase;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
+struct bGPDspoint;
struct bGPDstroke;
+struct Material;
struct bGPDpalette;
struct bGPDpalettecolor;
struct Main;
+struct BoundBox;
+struct Brush;
+struct Object;
+struct bDeformGroup;
+struct SimplifyGpencilModifierData;
+struct InstanceGpencilModifierData;
+struct LatticeGpencilModifierData;
+
+struct MDeformVert;
+struct MDeformWeight;
/* ------------ Grease-Pencil API ------------------ */
+void BKE_gpencil_free_point_weights(struct MDeformVert *dvert);
+void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps);
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
void BKE_gpencil_free_layers(struct ListBase *list);
-void BKE_gpencil_free_brushes(struct ListBase *list);
-void BKE_gpencil_free_palettes(struct ListBase *list);
-void BKE_gpencil_free(struct bGPdata *gpd, bool free_palettes);
+bool BKE_gpencil_free_frame_runtime_data(struct bGPDframe *derived_gpf);
+void BKE_gpencil_free_derived_frames(struct bGPdata *gpd);
+void BKE_gpencil_free(struct bGPdata *gpd, bool free_all);
+
+void BKE_gpencil_batch_cache_dirty(struct bGPdata *gpd);
+void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
void BKE_gpencil_stroke_sync_selection(struct bGPDstroke *gps);
@@ -60,21 +80,36 @@ 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);
+
void BKE_gpencil_copy_data(struct Main *bmain, 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);
void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local);
void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
-struct bGPDpalette *BKE_gpencil_palette_addnew(struct bGPdata *gpd, const char *name, bool setactive);
-struct bGPDpalette *BKE_gpencil_palette_duplicate(const struct bGPDpalette *palette_src);
-struct bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(struct bGPDpalette *palette, const char *name, bool setactive);
+/* materials */
+void BKE_gpencil_material_index_remove(struct bGPdata *gpd, int index);
+void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len);
-struct bGPDbrush *BKE_gpencil_brush_addnew(struct ToolSettings *ts, const char *name, bool setactive);
-struct bGPDbrush *BKE_gpencil_brush_duplicate(const struct bGPDbrush *brush_src);
-void BKE_gpencil_brush_init_presets(struct ToolSettings *ts);
+/* statistics functions */
+void BKE_gpencil_stats_update(struct bGPdata *gpd);
+/* Utilities for creating and populating GP strokes */
+/* - Number of values defining each point in the built-in data
+ * buffers for primitives (e.g. 2D Monkey)
+ */
+#define GP_PRIM_DATABUF_SIZE 5
+
+void BKE_gpencil_stroke_add_points(
+ struct bGPDstroke *gps,
+ const float *array, const int totpoints,
+ const float mat[4][4]);
+
+struct bGPDstroke *BKE_gpencil_add_stroke(struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness);
/* Stroke and Fill - Alpha Visibility Threshold */
#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
@@ -103,20 +138,40 @@ struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd);
void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
-struct bGPDbrush *BKE_gpencil_brush_getactive(struct ToolSettings *ts);
-void BKE_gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active);
-void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *brush);
-
-struct bGPDpalette *BKE_gpencil_palette_getactive(struct bGPdata *gpd);
-void BKE_gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active);
-void BKE_gpencil_palette_delete(struct bGPdata *gpd, struct bGPDpalette *palette);
-void BKE_gpencil_palette_change_strokes(struct bGPdata *gpd);
-
-struct bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(struct bGPDpalette *palette);
-void BKE_gpencil_palettecolor_setactive(struct bGPDpalette *palette, struct bGPDpalettecolor *active);
-void BKE_gpencil_palettecolor_delete(struct bGPDpalette *palette, struct bGPDpalettecolor *palcolor);
-struct bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(struct bGPDpalette *palette, char *name);
-void BKE_gpencil_palettecolor_changename(struct bGPdata *gpd, char *oldname, const char *newname);
-void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name);
+struct Material *BKE_gpencil_get_material_from_brush(struct Brush *brush);
+struct Material *BKE_gpencil_material_ensure(struct Main *bmain, struct Object *ob);
+
+/* object boundbox */
+bool BKE_gpencil_stroke_minmax(
+ const struct bGPDstroke *gps, const bool use_select,
+ float r_min[3], float r_max[3]);
+
+struct BoundBox *BKE_gpencil_boundbox_get(struct Object *ob);
+void BKE_gpencil_centroid_3D(struct bGPdata *gpd, float r_centroid[3]);
+
+/* vertex groups */
+float BKE_gpencil_vgroup_use_index(struct MDeformVert *dvert, int index);
+void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
+struct MDeformWeight *BKE_gpencil_vgroup_add_point_weight(struct MDeformVert *dvert, int index, float weight);
+bool BKE_gpencil_vgroup_remove_point_weight(struct MDeformVert *dvert, int index);
+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);
+
+/* 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_transform(struct bGPdata *gpd, float mat[4][4]);
+
+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);
+
+void BKE_gpencil_get_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);
#endif /* __BKE_GPENCIL_H__ */
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
new file mode 100644
index 00000000000..cd6b6540012
--- /dev/null
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -0,0 +1,256 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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: all of this file.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_GPENCIL_MODIFIER_H__
+#define __BKE_GPENCIL_MODIFIER_H__
+
+/** \file BKE_greasepencil_modifier.h
+ * \ingroup bke
+ */
+
+#include "DNA_gpencil_modifier_types.h" /* needed for all enum typdefs */
+#include "BLI_compiler_attrs.h"
+#include "BKE_customdata.h"
+
+struct ID;
+struct Depsgraph;
+struct DerivedMesh;
+struct bContext; /* NOTE: bakeModifier() - called from UI - needs to create new datablocks, hence the need for this */
+struct Mesh;
+struct Object;
+struct Scene;
+struct ViewLayer;
+struct ListBase;
+struct bArmature;
+struct Main;
+struct GpencilModifierData;
+struct BMEditMesh;
+struct DepsNodeHandle;
+struct bGPDlayer;
+struct bGPDframe;
+struct bGPDstroke;
+struct ModifierUpdateDepsgraphContext;
+
+#define GPENCIL_MODIFIER_ACTIVE(_md, _is_render) (((_md->mode & eGpencilModifierMode_Realtime) && (_is_render == false)) || \
+ ((_md->mode & eGpencilModifierMode_Render) && (_is_render == true)))
+#define GPENCIL_MODIFIER_EDIT(_md, _is_edit) (((_md->mode & eGpencilModifierMode_Editmode) == 0) && (_is_edit))
+
+typedef enum {
+ /* Should not be used, only for None modifier type */
+ eGpencilModifierTypeType_None,
+
+ /* grease pencil modifiers */
+ eGpencilModifierTypeType_Gpencil,
+} GpencilModifierTypeType;
+
+typedef enum {
+ eGpencilModifierTypeFlag_SupportsMapping = (1 << 0),
+ eGpencilModifierTypeFlag_SupportsEditmode = (1 << 1),
+
+ /* For modifiers that support editmode this determines if the
+ * modifier should be enabled by default in editmode. This should
+ * only be used by modifiers that are relatively speedy and
+ * also generally used in editmode, otherwise let the user enable
+ * it by hand.
+ */
+ eGpencilModifierTypeFlag_EnableInEditmode = (1 << 2),
+
+ /* For modifiers that require original data and so cannot
+ * be placed after any non-deformative modifier.
+ */
+ eGpencilModifierTypeFlag_RequiresOriginalData = (1 << 3),
+
+ /* max one per type */
+ eGpencilModifierTypeFlag_Single = (1 << 4),
+
+ /* can't be added manually by user */
+ eGpencilModifierTypeFlag_NoUserAdd = (1 << 5),
+} GpencilModifierTypeFlag;
+
+/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
+typedef void(*GreasePencilObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag);
+typedef void(*GreasePencilIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
+typedef void(*GreasePencilTexWalkFunc)(void *userData, struct Object *ob, struct GpencilModifierData *md, const char *propname);
+
+typedef struct GpencilModifierTypeInfo {
+ /* The user visible name for this modifier */
+ char name[32];
+
+ /* The DNA struct name for the modifier data type, used to
+ * write the DNA data out.
+ */
+ char struct_name[32];
+
+ /* The size of the modifier data type, used by allocation. */
+ int struct_size;
+
+ GpencilModifierType type;
+ GpencilModifierTypeFlag flags;
+
+
+ /********************* Non-optional functions *********************/
+
+ /* Copy instance data for this modifier type. Should copy all user
+ * level settings to the target modifier.
+ */
+ void (*copyData)(const struct GpencilModifierData *md, struct GpencilModifierData *target);
+
+ /* Callback for GP "stroke" modifiers that operate on the
+ * shape and parameters of the provided strokes (e.g. Thickness, Noise, etc.)
+ *
+ * The gpl parameter contains the GP layer that the strokes come from.
+ * While access is provided to this data, you should not directly access
+ * the gpl->frames data from the modifier. Instead, use the gpf parameter
+ * instead.
+ *
+ * The gps parameter contains the GP stroke to operate on. This is usually a copy
+ * of the original (unmodified and saved to files) stroke data.
+ */
+ void (*deformStroke)(struct GpencilModifierData *md, struct Depsgraph *depsgraph,
+ struct Object *ob, struct bGPDlayer *gpl, struct bGPDstroke *gps);
+
+ /* 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);
+
+ /* Bake-down GP modifier's effects into the GP datablock.
+ *
+ * This gets called when the user clicks the "Apply" button in the UI.
+ * As such, this callback needs to go through all layers/frames in the
+ * datablock, mutating the geometry and/or creating new datablocks/objects
+ */
+ void (*bakeModifier)(struct Main *bmain, struct Depsgraph *depsgraph,
+ struct GpencilModifierData *md, struct Object *ob);
+
+ /********************* Optional functions *********************/
+
+ /* Initialize new instance data for this modifier type, this function
+ * should set modifier variables to their default values.
+ *
+ * This function is optional.
+ */
+ void (*initData)(struct GpencilModifierData *md);
+
+ /* Free internal modifier data variables, this function should
+ * not free the md variable itself.
+ *
+ * This function is optional.
+ */
+ void (*freeData)(struct GpencilModifierData *md);
+
+ /* Return a boolean value indicating if this modifier is able to be
+ * calculated based on the modifier data. This is *not* regarding the
+ * md->flag, that is tested by the system, this is just if the data
+ * validates (for example, a lattice will return false if the lattice
+ * object is not defined).
+ *
+ * This function is optional (assumes never disabled if not present).
+ */
+ bool (*isDisabled)(struct GpencilModifierData *md, int userRenderParams);
+
+ /* Add the appropriate relations to the dependency graph.
+ *
+ * This function is optional.
+ */
+ void (*updateDepsgraph)(struct GpencilModifierData *md,
+ const struct ModifierUpdateDepsgraphContext *ctx);
+
+ /* Should return true if the modifier needs to be recalculated on time
+ * changes.
+ *
+ * This function is optional (assumes false if not present).
+ */
+ bool (*dependsOnTime)(struct GpencilModifierData *md);
+
+
+ /* Should call the given walk function on with a pointer to each Object
+ * pointer that the modifier data stores. This is used for linking on file
+ * load and for unlinking objects or forwarding object references.
+ *
+ * This function is optional.
+ */
+ void (*foreachObjectLink)(struct GpencilModifierData *md, struct Object *ob,
+ GreasePencilObjectWalkFunc walk, void *userData);
+
+ /* Should call the given walk function with a pointer to each ID
+ * pointer (i.e. each datablock pointer) that the modifier data
+ * stores. This is used for linking on file load and for
+ * unlinking datablocks or forwarding datablock references.
+ *
+ * This function is optional. If it is not present, foreachObjectLink
+ * will be used.
+ */
+ void (*foreachIDLink)(struct GpencilModifierData *md, struct Object *ob,
+ GreasePencilIDWalkFunc walk, void *userData);
+
+ /* Should call the given walk function for each texture that the
+ * modifier data stores. This is used for finding all textures in
+ * the context for the UI.
+ *
+ * This function is optional. If it is not present, it will be
+ * assumed the modifier has no textures.
+ */
+ void (*foreachTexLink)(struct GpencilModifierData *md, struct Object *ob,
+ GreasePencilTexWalkFunc walk, void *userData);
+} GpencilModifierTypeInfo;
+
+void BKE_gpencil_instance_modifier_instance_tfm(struct InstanceGpencilModifierData *mmd, const int elem_idx[3], float r_mat[4][4]);
+
+/* Initialize modifier's global data (type info and some common global storages). */
+void BKE_gpencil_modifier_init(void);
+
+const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type);
+struct GpencilModifierData *BKE_gpencil_modifier_new(int type);
+void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag);
+void BKE_gpencil_modifier_free(struct GpencilModifierData *md);
+bool BKE_gpencil_modifier_unique_name(struct ListBase *modifiers, struct GpencilModifierData *gmd);
+bool BKE_gpencil_modifier_dependsOnTime(struct GpencilModifierData *md);
+struct GpencilModifierData *BKE_gpencil_modifiers_findByType(struct Object *ob, GpencilModifierType type);
+struct GpencilModifierData *BKE_gpencil_modifiers_findByName(struct Object *ob, const char *name);
+void BKE_gpencil_modifier_copyData_generic(const struct GpencilModifierData *md_src, struct GpencilModifierData *md_dst);
+void BKE_gpencil_modifier_copyData(struct GpencilModifierData *md, struct GpencilModifierData *target);
+void BKE_gpencil_modifier_copyData_ex(struct GpencilModifierData *md, struct GpencilModifierData *target, const int flag);
+void BKE_gpencil_modifiers_foreachIDLink(struct Object *ob, GreasePencilIDWalkFunc walk, void *userData);
+void BKE_gpencil_modifiers_foreachTexLink(struct Object *ob, GreasePencilTexWalkFunc walk, void *userData);
+
+bool BKE_gpencil_has_geometry_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);
+
+void BKE_gpencil_lattice_init(struct Object *ob);
+void BKE_gpencil_lattice_clear(struct Object *ob);
+
+#endif /* __BKE_GPENCIL_MODIFIER_H__ */
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 22897d2ea80..7a5262e0a14 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -43,7 +43,10 @@ enum {
ICON_DATA_PREVIEW,
/** 2D triangles: obj is #Icon_Geom */
ICON_DATA_GEOM,
+ /** Studiolight */
ICON_DATA_STUDIOLIGHT,
+ /** GPencil Layer color preview (annotations): obj is #bGPDlayer */
+ ICON_DATA_GPLAYER,
};
struct Icon {
@@ -79,6 +82,7 @@ struct ImBuf;
struct PreviewImage;
struct ID;
struct StudioLight;
+struct bGPDlayer;
enum eIconSizes;
@@ -87,6 +91,9 @@ void BKE_icons_init(int first_dyn_id);
/* return icon id for library object or create new icon if not found */
int BKE_icon_id_ensure(struct ID *id);
+/* return icon id for Grease Pencil layer (color preview) or create new icon if not found */
+int BKE_icon_gplayer_color_ensure(struct bGPDlayer *gpl);
+
int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview);
/* retrieve icon for id */
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index c2ac5e98f76..67e6a32edfd 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -54,7 +54,6 @@ void BKE_lattice_free(struct Lattice *lt);
void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt, const bool lib_local);
void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du);
-struct LatticeDeformData;
struct LatticeDeformData *init_latt_deform(struct Object *oblatt, struct Object *ob) ATTR_WARN_UNUSED_RESULT;
void calc_latt_deform(struct LatticeDeformData *lattice_deform_data, float co[3], float weight);
void end_latt_deform(struct LatticeDeformData *lattice_deform_data);
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index c85017a2216..1ca8928c61d 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -54,11 +54,13 @@ void BKE_material_init(struct Material *ma);
void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst);
struct Material *BKE_material_add(struct Main *bmain, const char *name);
+struct Material *BKE_material_add_gpencil(struct Main *bmain, const char *name);
void BKE_material_copy_data(struct Main *bmain, struct Material *ma_dst, const struct Material *ma_src, const int flag);
struct Material *BKE_material_copy(struct Main *bmain, const struct Material *ma);
struct Material *BKE_material_localize(struct Material *ma);
struct Material *give_node_material(struct Material *ma); /* returns node material or self */
void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool lib_local);
+void BKE_material_init_gpencil_settings(struct Material *ma);
/* UNUSED */
// void automatname(struct Material *);
@@ -87,6 +89,8 @@ short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma
bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob);
+struct MaterialGPencilStyle *BKE_material_gpencil_settings_get(struct Object *ob, short act);
+
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 79e4f1d448a..7d795c25a04 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -37,8 +37,11 @@ extern "C" {
struct Base;
struct Depsgraph;
+struct GpencilModifierData;
struct Scene;
+struct ShaderFxData;
struct ViewLayer;
+struct ID;
struct Object;
struct BoundBox;
struct View3D;
@@ -49,6 +52,7 @@ struct Mesh;
struct RigidBodyWorld;
struct HookModifierData;
struct ModifierData;
+struct HookGpencilModifierData;
#include "DNA_object_enums.h"
@@ -69,11 +73,16 @@ void BKE_object_free_derived_mesh_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
+void BKE_object_modifier_gpencil_hook_reset(struct Object *ob, struct HookGpencilModifierData *hmd);
+bool BKE_object_modifier_gpencil_use_time(struct Object *ob, struct GpencilModifierData *md);
+
+bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md);
bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type);
void BKE_object_link_modifiers(struct Scene *scene, struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_free_modifiers(struct Object *ob, const int flag);
+void BKE_object_free_shaderfx(struct Object *ob, const int flag);
void BKE_object_make_proxy(struct Main *bmain, struct Object *ob, struct Object *target, struct Object *gob);
void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
@@ -108,6 +117,9 @@ struct Object *BKE_object_add_from(
struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer,
int type, const char *name, struct Object *ob_src)
ATTR_NONNULL(1, 2, 3, 6) ATTR_RETURNS_NONNULL;
+struct Object *BKE_object_add_for_data(
+ struct Main *bmain, struct ViewLayer *view_layer,
+ int type, const char *name, struct ID *data, bool do_id_user) ATTR_RETURNS_NONNULL;
void *BKE_object_obdata_add_from_type(
struct Main *bmain,
int type, const char *name)
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 6ade14b275c..c440a634c9f 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -77,7 +77,8 @@ typedef enum ePaintMode {
ePaintTextureProjective = 3,
ePaintTexture2D = 4,
ePaintSculptUV = 5,
- ePaintInvalid = 6
+ ePaintInvalid = 6,
+ ePaintGpencil = 7
} ePaintMode;
/* overlay invalidation */
diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h
new file mode 100644
index 00000000000..11c5983106a
--- /dev/null
+++ b/source/blender/blenkernel/BKE_shader_fx.h
@@ -0,0 +1,180 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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: all of this file.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_SHADER_FX_H__
+#define __BKE_SHADER_FX_H__
+
+/** \file BKE_shader_fx.h
+ * \ingroup bke
+ */
+
+#include "DNA_shader_fx_types.h" /* needed for all enum typdefs */
+#include "BLI_compiler_attrs.h"
+#include "BKE_customdata.h"
+
+struct ID;
+struct Depsgraph;
+struct DerivedMesh;
+struct Mesh;
+struct Object;
+struct Scene;
+struct ViewLayer;
+struct ListBase;
+struct bArmature;
+struct Main;
+struct ShaderFxData;
+struct DepsNodeHandle;
+struct bGPDlayer;
+struct bGPDframe;
+struct bGPDstroke;
+struct ModifierUpdateDepsgraphContext;
+
+#define SHADER_FX_ACTIVE(_fx, _is_render) (((_fx->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \
+ ((_fx->mode & eShaderFxMode_Render) && (_is_render == true)))
+#define SHADER_FX_EDIT(_fx, _is_edit) (((_fx->mode & eShaderFxMode_Editmode) == 0) && (_is_edit))
+
+typedef enum {
+ /* Should not be used, only for None type */
+ eShaderFxType_NoneType,
+
+ /* grease pencil effects */
+ eShaderFxType_GpencilType,
+} ShaderFxTypeType;
+
+typedef enum {
+ eShaderFxTypeFlag_SupportsEditmode = (1 << 0),
+
+ /* For effects that support editmode this determines if the
+ * effect should be enabled by default in editmode.
+ */
+ eShaderFxTypeFlag_EnableInEditmode = (1 << 2),
+
+ /* max one per type */
+ eShaderFxTypeFlag_Single = (1 << 4),
+
+ /* can't be added manually by user */
+ eShaderFxTypeFlag_NoUserAdd = (1 << 5),
+} ShaderFxTypeFlag;
+
+/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
+typedef void(*ShaderFxObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag);
+typedef void(*ShaderFxIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
+typedef void(*ShaderFxTexWalkFunc)(void *userData, struct Object *ob, struct ShaderFxData *fx, const char *propname);
+
+typedef struct ShaderFxTypeInfo {
+ /* The user visible name for this effect */
+ char name[32];
+
+ /* The DNA struct name for the effect data type, used to
+ * write the DNA data out.
+ */
+ char struct_name[32];
+
+ /* The size of the effect data type, used by allocation. */
+ int struct_size;
+
+ ShaderFxTypeType type;
+ ShaderFxTypeFlag flags;
+
+ /* Copy instance data for this effect type. Should copy all user
+ * level settings to the target effect.
+ */
+ void(*copyData)(const struct ShaderFxData *fx, struct ShaderFxData *target);
+
+ /* Initialize new instance data for this effect type, this function
+ * should set effect variables to their default values.
+ *
+ * This function is optional.
+ */
+ void (*initData)(struct ShaderFxData *fx);
+
+ /* Free internal effect data variables, this function should
+ * not free the fx variable itself.
+ *
+ * This function is optional.
+ */
+ void (*freeData)(struct ShaderFxData *fx);
+
+ /* Return a boolean value indicating if this effect is able to be
+ * calculated based on the effect data. This is *not* regarding the
+ * fx->flag, that is tested by the system, this is just if the data
+ * validates (for example, a lattice will return false if the lattice
+ * object is not defined).
+ *
+ * This function is optional (assumes never disabled if not present).
+ */
+ bool (*isDisabled)(struct ShaderFxData *fx, int userRenderParams);
+
+ /* Add the appropriate relations to the dependency graph.
+ *
+ * This function is optional.
+ */
+ void (*updateDepsgraph)(struct ShaderFxData *fx,
+ const struct ModifierUpdateDepsgraphContext *ctx);
+
+ /* Should return true if the effect needs to be recalculated on time
+ * changes.
+ *
+ * This function is optional (assumes false if not present).
+ */
+ bool (*dependsOnTime)(struct ShaderFxData *fx);
+
+
+ /* Should call the given walk function on with a pointer to each Object
+ * pointer that the effect data stores. This is used for linking on file
+ * load and for unlinking objects or forwarding object references.
+ *
+ * This function is optional.
+ */
+ void (*foreachObjectLink)(struct ShaderFxData *fx, struct Object *ob,
+ ShaderFxObjectWalkFunc walk, void *userData);
+
+ /* Should call the given walk function with a pointer to each ID
+ * pointer (i.e. each datablock pointer) that the effect data
+ * stores. This is used for linking on file load and for
+ * unlinking datablocks or forwarding datablock references.
+ *
+ * This function is optional. If it is not present, foreachObjectLink
+ * will be used.
+ */
+ void (*foreachIDLink)(struct ShaderFxData *fx, struct Object *ob,
+ ShaderFxIDWalkFunc walk, void *userData);
+} ShaderFxTypeInfo;
+
+/* Initialize global data (type info and some common global storages). */
+void BKE_shaderfx_init(void);
+
+const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type);
+struct ShaderFxData *BKE_shaderfx_new(int type);
+void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag);
+void BKE_shaderfx_free(struct ShaderFxData *fx);
+bool BKE_shaderfx_unique_name(struct ListBase *shaderfx, struct ShaderFxData *fx);
+bool BKE_shaderfx_dependsOnTime(struct ShaderFxData *fx);
+struct ShaderFxData *BKE_shaderfx_findByType(struct Object *ob, ShaderFxType type);
+struct ShaderFxData *BKE_shaderfx_findByName(struct Object *ob, const char *name);
+void BKE_shaderfx_copyData_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst);
+void BKE_shaderfx_copyData(struct ShaderFxData *fx, struct ShaderFxData *target);
+void BKE_shaderfx_copyData_ex(struct ShaderFxData *fx, struct ShaderFxData *target, const int flag);
+void BKE_shaderfx_foreachIDLink(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
+
+bool BKE_shaderfx_has_gpencil(struct Object *ob);
+
+#endif /* __BKE_SHADER_FX_H__ */
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 01910bffdb0..7169597f100 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -38,6 +38,8 @@ set(INC
../makesrna
../bmesh
../modifiers
+ ../gpencil_modifiers
+ ../shader_fx
../nodes
../physics
../render/extern/include
@@ -115,6 +117,7 @@ set(SRC
intern/font.c
intern/freestyle.c
intern/gpencil.c
+ intern/gpencil_modifier.c
intern/icons.c
intern/icons_rasterize.c
intern/idcode.c
@@ -180,6 +183,7 @@ set(SRC
intern/seqeffects.c
intern/seqmodifier.c
intern/sequencer.c
+ intern/shader_fx.c
intern/shrinkwrap.c
intern/smoke.c
intern/softbody.c
@@ -259,6 +263,7 @@ set(SRC
BKE_freestyle.h
BKE_global.h
BKE_gpencil.h
+ BKE_gpencil_modifier.h
BKE_icons.h
BKE_idcode.h
BKE_idprop.h
@@ -306,6 +311,7 @@ set(SRC
BKE_scene.h
BKE_screen.h
BKE_sequencer.h
+ BKE_shader_fx.h
BKE_shrinkwrap.h
BKE_smoke.h
BKE_softbody.h
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index fd7497f9ba1..7dfedfe6c06 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -104,6 +104,7 @@ bool id_type_can_have_animdata(const short id_type)
case ID_MSK:
case ID_GD:
case ID_CF:
+ case ID_PAL:
return true;
/* no AnimData */
@@ -1150,6 +1151,9 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use
/* grease pencil */
ANIMDATA_IDS_CB(bmain->gpencil.first);
+ /* palettes */
+ ANIMDATA_IDS_CB(bmain->palettes.first);
+
/* cache files */
ANIMDATA_IDS_CB(bmain->cachefiles.first);
}
@@ -2925,6 +2929,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, Scene
/* grease pencil */
EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM);
+ /* palettes */
+ EVAL_ANIM_IDS(main->palettes.first, ADT_RECALC_ANIM);
+
/* cache files */
EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM);
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 42cd7968321..598eb9b5b54 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -29,6 +29,7 @@
#include "DNA_brush_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
@@ -36,6 +37,7 @@
#include "BKE_brush.h"
#include "BKE_colortools.h"
+#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -129,6 +131,7 @@ static void brush_defaults(Brush *brush)
brush->stencil_dimension[0] = 256;
brush->stencil_dimension[1] = 256;
+
}
/* Datablock add/copy/free/make_local */
@@ -164,6 +167,368 @@ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
return brush;
}
+/* add a new gp-brush */
+Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name)
+{
+ Brush *brush;
+ Paint *paint = BKE_brush_get_gpencil_paint(ts);
+ brush = BKE_brush_add(bmain, name, OB_MODE_GPENCIL_PAINT);
+
+ BKE_paint_brush_set(paint, brush);
+ id_us_min(&brush->id);
+
+ /* grease pencil basic settings */
+ brush->size = 3;
+
+ brush->gpencil_settings = MEM_callocN(sizeof(BrushGpencilSettings), "BrushGpencilSettings");
+
+ 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;
+
+ /* curves */
+ brush->gpencil_settings->curve_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+
+ /* return brush */
+ return brush;
+}
+
+Paint *BKE_brush_get_gpencil_paint(ToolSettings *ts)
+{
+ /* alloc paint session */
+ if (ts->gp_paint == NULL) {
+ ts->gp_paint = MEM_callocN(sizeof(GpPaint), "GpPaint");
+ }
+
+ return &ts->gp_paint->paint;
+}
+
+/* grease pencil cumapping->preset */
+typedef enum eGPCurveMappingPreset {
+ GPCURVE_PRESET_PENCIL = 0,
+ GPCURVE_PRESET_INK = 1,
+ GPCURVE_PRESET_INKNOISE = 2,
+} eGPCurveMappingPreset;
+
+static void brush_gpencil_curvemap_reset(CurveMap *cuma, int preset)
+{
+ if (cuma->curve)
+ MEM_freeN(cuma->curve);
+
+ cuma->totpoint = 3;
+ cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), __func__);
+
+ switch (preset) {
+ case GPCURVE_PRESET_PENCIL:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.75115f;
+ cuma->curve[1].y = 0.25f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ case GPCURVE_PRESET_INK:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.63448f;
+ cuma->curve[1].y = 0.375f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ case GPCURVE_PRESET_INKNOISE:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.63134f;
+ cuma->curve[1].y = 0.3625f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ }
+
+ if (cuma->table) {
+ MEM_freeN(cuma->table);
+ cuma->table = NULL;
+ }
+}
+
+/* create a set of grease pencil presets */
+void BKE_brush_gpencil_presets(bContext *C)
+{
+#define SMOOTH_STROKE_RADIUS 40
+#define SMOOTH_STROKE_FACTOR 0.9f
+
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Paint *paint = BKE_brush_get_gpencil_paint(ts);
+ Main *bmain = CTX_data_main(C);
+
+ Brush *brush, *deft;
+ CurveMapping *custom_curve;
+
+ /* Pencil brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pencil");
+ brush->size = 25.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 0.6f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ 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_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.5f;
+ 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->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Pen brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen");
+ deft = brush; /* save default brush */
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ 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_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.5f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Ink brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink");
+ brush->size = 60.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.6f;
+
+ brush->gpencil_settings->draw_strength = 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_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.5f;
+ 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->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Curve */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INK);
+
+ /* Ink Noise brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Noise");
+ brush->size = 60.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.7f;
+ 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_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 1.0f;
+ brush->gpencil_settings->draw_smoothlvl = 2;
+ brush->gpencil_settings->thick_smoothfac = 0.5f;
+ brush->gpencil_settings->thick_smoothlvl = 2;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Curve */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INKNOISE);
+
+ /* Block Basic brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block");
+ brush->size = 150.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 0.7f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ 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_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.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 = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
+ brush->gpencil_settings->draw_random_sub = 0;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Marker brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker");
+ brush->size = 80.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.374f;
+ 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_angle = M_PI_4; /* 45 degrees */
+ brush->gpencil_settings->draw_angle_factor = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.5f;
+ 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->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Fill brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area");
+ brush->size = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->fill_leak = 3;
+ brush->gpencil_settings->fill_threshold = 0.1f;
+ brush->gpencil_settings->fill_simplylvl = 1;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_FILL;
+
+ brush->gpencil_settings->draw_smoothfac = 0.5f;
+ 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->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ /* Soft Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft");
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
+
+ /* Hard Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard");
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
+
+ /* Stroke Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke");
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
+
+ /* set defaut brush */
+ BKE_paint_brush_set(paint, deft);
+
+}
+
+/* get the active gp-brush for editing */
+Brush *BKE_brush_getactive_gpencil(ToolSettings *ts)
+{
+ /* error checking */
+ if (ELEM(NULL, ts, ts->gp_paint)) {
+ return NULL;
+ }
+ Paint *paint = &ts->gp_paint->paint;
+
+ return paint->brush;
+}
+
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
{
Brush *brush;
@@ -197,6 +562,12 @@ void BKE_brush_copy_data(Main *UNUSED(bmain), Brush *brush_dst, const Brush *bru
}
brush_dst->curve = curvemapping_copy(brush_src->curve);
+ if (brush_src->gpencil_settings != NULL) {
+ brush_dst->gpencil_settings = MEM_dupallocN(brush_src->gpencil_settings);
+ brush_dst->gpencil_settings->curve_sensitivity = curvemapping_copy(brush_src->gpencil_settings->curve_sensitivity);
+ brush_dst->gpencil_settings->curve_strength = curvemapping_copy(brush_src->gpencil_settings->curve_strength);
+ brush_dst->gpencil_settings->curve_jitter = curvemapping_copy(brush_src->gpencil_settings->curve_jitter);
+ }
/* enable fake user by default */
id_fake_user_set(&brush_dst->id);
@@ -215,11 +586,18 @@ void BKE_brush_free(Brush *brush)
if (brush->icon_imbuf) {
IMB_freeImBuf(brush->icon_imbuf);
}
-
curvemapping_free(brush->curve);
+ if (brush->gpencil_settings != NULL) {
+ curvemapping_free(brush->gpencil_settings->curve_sensitivity);
+ curvemapping_free(brush->gpencil_settings->curve_strength);
+ curvemapping_free(brush->gpencil_settings->curve_jitter);
+ MEM_SAFE_FREE(brush->gpencil_settings);
+ }
+
MEM_SAFE_FREE(brush->gradient);
+
BKE_previewimg_free(&(brush->preview));
}
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index ff4795afe87..d18572a57f6 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -282,6 +282,7 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
case CURVE_PRESET_MID9: cuma->totpoint = 9; break;
case CURVE_PRESET_ROUND: cuma->totpoint = 4; break;
case CURVE_PRESET_ROOT: cuma->totpoint = 4; break;
+ case CURVE_PRESET_GAUSS: cuma->totpoint = 7; break;
}
cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), "curve points");
@@ -352,6 +353,24 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
cuma->curve[3].x = 1;
cuma->curve[3].y = 0;
break;
+ case CURVE_PRESET_GAUSS:
+ cuma->curve[0].x = 0;
+ cuma->curve[0].y = 0.025f;
+ cuma->curve[1].x = 0.16f;
+ cuma->curve[1].y = 0.135f;
+ cuma->curve[2].x = 0.298f;
+ cuma->curve[2].y = 0.36f;
+
+ cuma->curve[3].x = 0.50f;
+ cuma->curve[3].y = 1.0f;
+
+ cuma->curve[4].x = 0.70f;
+ cuma->curve[4].y = 0.36f;
+ cuma->curve[5].x = 0.84f;
+ cuma->curve[5].y = 0.135f;
+ cuma->curve[6].x = 1.0f;
+ cuma->curve[6].y = 0.025f;
+ break;
}
/* mirror curve in x direction to have positive slope
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 3dfe9732062..84ca143dc55 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -1014,6 +1014,10 @@ int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob, const eObjectM
else if (object_mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX;
else if (object_mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE;
else if (object_mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE;
+ else if (object_mode & OB_MODE_GPENCIL_PAINT) return CTX_MODE_GPENCIL_PAINT;
+ else if (object_mode & OB_MODE_GPENCIL_EDIT) return CTX_MODE_GPENCIL_EDIT;
+ else if (object_mode & OB_MODE_GPENCIL_SCULPT) return CTX_MODE_GPENCIL_SCULPT;
+ else if (object_mode & OB_MODE_GPENCIL_WEIGHT) return CTX_MODE_GPENCIL_WEIGHT;
}
}
@@ -1044,6 +1048,10 @@ static const char *data_mode_strings[] = {
"imagepaint",
"particlemode",
"objectmode",
+ "greasepencil_paint",
+ "greasepencil_edit",
+ "greasepencil_sculpt",
+ "greasepencil_weight",
NULL
};
BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1, "Must have a string for each context mode")
@@ -1212,17 +1220,7 @@ bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C)
return ctx_data_pointer_get(C, "active_gpencil_layer");
}
-bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C)
-{
- return ctx_data_pointer_get(C, "active_gpencil_palette");
-}
-
-bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C)
-{
- return ctx_data_pointer_get(C, "active_gpencil_palettecolor");
-}
-
-bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C)
+Brush *CTX_data_active_gpencil_brush(const bContext *C)
{
return ctx_data_pointer_get(C, "active_gpencil_brush");
}
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index d08e3643ca7..ddf9840a32e 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -74,7 +74,9 @@ bDeformGroup *BKE_defgroup_new(Object *ob, const char *name)
BLI_addtail(&ob->defbase, defgroup);
defgroup_unique_name(defgroup, ob);
- BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ if (ob->type != OB_GPENCIL) {
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ }
return defgroup;
}
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index e89508fd6c0..de3f891f9f9 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -39,26 +39,83 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
+#include "BLI_math_color.h"
#include "BLI_string_utils.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
#include "BLT_translation.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_object_types.h"
+#include "BKE_context.h"
+#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_colortools.h"
+#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_material.h"
+#include "DEG_depsgraph.h"
/* ************************************************** */
-/* GENERAL STUFF */
+/* Draw Engine */
-/* --------- Memory Management ------------ */
+void(*BKE_gpencil_batch_cache_dirty_cb)(bGPdata *gpd) = NULL;
+void(*BKE_gpencil_batch_cache_free_cb)(bGPdata *gpd) = NULL;
+
+void BKE_gpencil_batch_cache_dirty(bGPdata *gpd)
+{
+ if (gpd) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+ BKE_gpencil_batch_cache_dirty_cb(gpd);
+ }
+}
+
+void BKE_gpencil_batch_cache_free(bGPdata *gpd)
+{
+ if (gpd) {
+ BKE_gpencil_batch_cache_free_cb(gpd);
+ }
+}
+
+/* ************************************************** */
+/* Memory Management */
+
+/* clean vertex groups weights */
+void BKE_gpencil_free_point_weights(MDeformVert *dvert)
+{
+ if (dvert == NULL) {
+ return;
+ }
+ MEM_SAFE_FREE(dvert->dw);
+}
+
+void BKE_gpencil_free_stroke_weights(bGPDstroke *gps)
+{
+ if (gps == NULL) {
+ return;
+ }
+
+ if (gps->dvert == NULL) {
+ return;
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ MDeformVert *dvert = &gps->dvert[i];
+ BKE_gpencil_free_point_weights(dvert);
+ }
+}
/* free stroke, doesn't unlink from any listbase */
void BKE_gpencil_free_stroke(bGPDstroke *gps)
@@ -66,10 +123,14 @@ void BKE_gpencil_free_stroke(bGPDstroke *gps)
if (gps == NULL) {
return;
}
-
/* free stroke memory arrays, then stroke itself */
- if (gps->points)
+ if (gps->points) {
MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
if (gps->triangles)
MEM_freeN(gps->triangles);
@@ -92,6 +153,26 @@ 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 *derived_gpf)
+{
+ bGPDstroke *gps_next;
+ if (!derived_gpf) {
+ return false;
+ }
+
+ /* free strokes */
+ for (bGPDstroke *gps = derived_gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+ BKE_gpencil_free_stroke(gps);
+ }
+ BLI_listbase_clear(&derived_gpf->strokes);
+
+ MEM_SAFE_FREE(derived_gpf);
+
+ return true;
+}
+
/* Free all of a gp-layer's frames */
void BKE_gpencil_free_frames(bGPDlayer *gpl)
{
@@ -111,101 +192,101 @@ void BKE_gpencil_free_frames(bGPDlayer *gpl)
gpl->actframe = NULL;
}
-/* Free all of a gp-colors */
-static void free_gpencil_colors(bGPDpalette *palette)
-{
- /* error checking */
- if (palette == NULL) {
- return;
- }
- /* free colors */
- BLI_freelistN(&palette->colors);
-}
-/* Free all of the gp-palettes and colors */
-void BKE_gpencil_free_palettes(ListBase *list)
+/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
+void BKE_gpencil_free_layers(ListBase *list)
{
- bGPDpalette *palette_next;
+ bGPDlayer *gpl_next;
/* error checking */
- if (list == NULL) {
- return;
- }
+ if (list == NULL) return;
- /* delete palettes */
- for (bGPDpalette *palette = list->first; palette; palette = palette_next) {
- palette_next = palette->next;
- /* free palette colors */
- free_gpencil_colors(palette);
+ /* delete layers */
+ for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) {
+ gpl_next = gpl->next;
- MEM_freeN(palette);
+ /* free layers and their data */
+ BKE_gpencil_free_frames(gpl);
+ BLI_freelinkN(list, gpl);
}
- BLI_listbase_clear(list);
}
-/* Free all of the gp-brushes for a viewport (list should be &gpd->brushes or so) */
-void BKE_gpencil_free_brushes(ListBase *list)
+/* clear all runtime derived data */
+static void BKE_gpencil_clear_derived(bGPDlayer *gpl)
{
- bGPDbrush *brush_next;
+ GHashIterator gh_iter;
- /* error checking */
- if (list == NULL) {
+ if (gpl->runtime.derived_data == NULL) {
return;
}
- /* delete brushes */
- for (bGPDbrush *brush = list->first; brush; brush = brush_next) {
- brush_next = brush->next;
- /* free curves */
- if (brush->cur_sensitivity) {
- curvemapping_free(brush->cur_sensitivity);
- }
- if (brush->cur_strength) {
- curvemapping_free(brush->cur_strength);
+ GHASH_ITER(gh_iter, gpl->runtime.derived_data) {
+ bGPDframe *gpf = (bGPDframe *)BLI_ghashIterator_getValue(&gh_iter);
+ if (gpf) {
+ BKE_gpencil_free_frame_runtime_data(gpf);
}
- if (brush->cur_jitter) {
- curvemapping_free(brush->cur_jitter);
- }
-
- MEM_freeN(brush);
}
- BLI_listbase_clear(list);
}
-/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
-void BKE_gpencil_free_layers(ListBase *list)
+/* Free all of the gp-layers temp data*/
+static void BKE_gpencil_free_layers_temp_data(ListBase *list)
{
bGPDlayer *gpl_next;
/* error checking */
if (list == NULL) return;
-
/* delete layers */
for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) {
gpl_next = gpl->next;
+ BKE_gpencil_clear_derived(gpl);
- /* free layers and their data */
- BKE_gpencil_free_frames(gpl);
- BLI_freelinkN(list, gpl);
+ if (gpl->runtime.derived_data) {
+ BLI_ghash_free(gpl->runtime.derived_data, NULL, NULL);
+ gpl->runtime.derived_data = NULL;
+ }
+ }
+}
+
+/* Free temp gpf derived frames */
+void BKE_gpencil_free_derived_frames(bGPdata *gpd)
+{
+ /* error checking */
+ if (gpd == NULL) return;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ BKE_gpencil_clear_derived(gpl);
+
+ if (gpl->runtime.derived_data) {
+ BLI_ghash_free(gpl->runtime.derived_data, NULL, NULL);
+ gpl->runtime.derived_data = NULL;
+ }
}
}
/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
-void BKE_gpencil_free(bGPdata *gpd, bool free_palettes)
+void BKE_gpencil_free(bGPdata *gpd, bool free_all)
{
+ /* clear animation data */
BKE_animdata_free(&gpd->id, false);
/* free layers */
+ if (free_all) {
+ BKE_gpencil_free_layers_temp_data(&gpd->layers);
+ }
BKE_gpencil_free_layers(&gpd->layers);
- /* free palettes */
- if (free_palettes) {
- BKE_gpencil_free_palettes(&gpd->palettes);
+ /* materials */
+ MEM_SAFE_FREE(gpd->mat);
+
+ /* free all data */
+ if (free_all) {
+ /* clear cache */
+ BKE_gpencil_batch_cache_free(gpd);
}
}
-/* -------- Container Creation ---------- */
+/* ************************************************** */
+/* Container Creation */
/* add a new gp-frame to the given layer */
bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
@@ -329,28 +410,31 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti
/* add to datablock */
BLI_addtail(&gpd->layers, gpl);
- /* set basic settings */
- copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
- /* Since GPv2 thickness must be 0 */
- gpl->thickness = 0;
-
- gpl->opacity = 1.0f;
+ /* annotation vs GP Object behaviour is slightly different */
+ if (gpd->flag & GP_DATA_ANNOTATIONS) {
+ /* set default color of new strokes for this layer */
+ copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
+ gpl->opacity = 1.0f;
- /* onion-skinning settings */
- if (gpd->flag & GP_DATA_SHOW_ONIONSKINS)
- gpl->flag |= GP_LAYER_ONIONSKIN;
+ /* set default thickness of new strokes for this layer */
+ gpl->thickness = 3;
- gpl->flag |= (GP_LAYER_GHOST_PREVCOL | GP_LAYER_GHOST_NEXTCOL);
-
- ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
- ARRAY_SET_ITEMS(gpl->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
-
- /* high quality fill by default */
- gpl->flag |= GP_LAYER_HQ_FILL;
+ /* onion-skinning settings */
+ gpl->onion_flag |= GP_LAYER_ONIONSKIN;
+ }
+ else {
+ /* thickness parameter represents "thickness change", not absolute thickness */
+ gpl->thickness = 0;
+ gpl->opacity = 1.0f;
+ }
/* auto-name */
BLI_strncpy(gpl->info, name, sizeof(gpl->info));
- BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
+ BLI_uniquename(&gpd->layers, gpl,
+ (gpd->flag & GP_DATA_ANNOTATIONS) ? DATA_("Note") : DATA_("GP_Layer"),
+ '.',
+ offsetof(bGPDlayer, info),
+ sizeof(gpl->info));
/* make this one the active one */
if (setactive)
@@ -360,292 +444,153 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti
return gpl;
}
-/* add a new gp-palette and make it the active */
-bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name, bool setactive)
-{
- bGPDpalette *palette;
-
- /* check that list is ok */
- if (gpd == NULL) {
- return NULL;
- }
-
- /* allocate memory and add to end of list */
- palette = MEM_callocN(sizeof(bGPDpalette), "bGPDpalette");
-
- /* add to datablock */
- BLI_addtail(&gpd->palettes, palette);
-
- /* set basic settings */
- /* auto-name */
- BLI_strncpy(palette->info, name, sizeof(palette->info));
- BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info),
- sizeof(palette->info));
-
- /* make this one the active one */
- /* NOTE: Always make this active if there's nothing else yet (T50123) */
- if ((setactive) || (gpd->palettes.first == gpd->palettes.last)) {
- BKE_gpencil_palette_setactive(gpd, palette);
- }
-
- /* return palette */
- return palette;
-}
-
-/* create a set of default drawing brushes with predefined presets */
-void BKE_gpencil_brush_init_presets(ToolSettings *ts)
+/* add a new gp-datablock */
+bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
{
- bGPDbrush *brush;
- /* Basic brush */
- brush = BKE_gpencil_brush_addnew(ts, "Basic", true);
- brush->thickness = 3.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.0f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
-
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag |= ~GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->draw_random_press = 0.0f;
-
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
-
- brush->draw_smoothfac = 0.0f;
- brush->draw_smoothlvl = 1;
- brush->sublevel = 0;
- brush->draw_random_sub = 0.0f;
-
- /* Pencil brush */
- brush = BKE_gpencil_brush_addnew(ts, "Pencil", false);
- brush->thickness = 7.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.0f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
-
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 0.7f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->draw_random_press = 0.0f;
-
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
-
- brush->draw_smoothfac = 1.0f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
-
- /* Ink brush */
- brush = BKE_gpencil_brush_addnew(ts, "Ink", false);
- brush->thickness = 7.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.6f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
-
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->draw_random_press = 0.0f;
-
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
+ bGPdata *gpd;
- brush->draw_smoothfac = 1.1f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
+ /* allocate memory for a new block */
+ gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0);
- /* Ink Noise brush */
- brush = BKE_gpencil_brush_addnew(ts, "Ink noise", false);
- brush->thickness = 6.0f;
- brush->flag |= GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.611f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
+ /* initial settings */
+ gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND);
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ /* general flags */
+ gpd->flag |= GP_DATA_VIEWALIGN;
- brush->draw_random_press = 1.0f;
+ /* GP object specific settings */
+ ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f);
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ gpd->xray_mode = GP_XRAY_3DSPACE;
+ gpd->runtime.batch_cache_data = NULL;
+ gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
+ /* onion-skinning settings (datablock level) */
+ gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL);
+ gpd->onion_flag |= GP_ONION_FADE;
+ gpd->onion_mode = GP_ONION_MODE_RELATIVE;
+ gpd->onion_factor = 0.5f;
+ ARRAY_SET_ITEMS(gpd->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
+ ARRAY_SET_ITEMS(gpd->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
+ gpd->gstep = 1;
+ gpd->gstep_next = 1;
- brush->draw_smoothfac = 1.1f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
+ return gpd;
+}
- /* Marker brush */
- brush = BKE_gpencil_brush_addnew(ts, "Marker", false);
- brush->thickness = 10.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 2.0f;
- brush->flag &= ~GP_BRUSH_USE_PRESSURE;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
+/* ************************************************** */
+/* Primitive Creation */
+/* Utilities for easier bulk-creation of geometry */
- brush->draw_random_press = 0.0f;
+/**
+ * Populate stroke with point data from data buffers
+ *
+ * \param array Flat array of point data values. Each entry has GP_PRIM_DATABUF_SIZE values
+ * \param mat 4x4 transform matrix to transform points into the right coordinate space
+ */
+void BKE_gpencil_stroke_add_points(bGPDstroke *gps, const float *array, const int totpoints, const float mat[4][4])
+{
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ const int x = GP_PRIM_DATABUF_SIZE * i;
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ pt->x = array[x];
+ pt->y = array[x + 1];
+ pt->z = array[x + 2];
+ mul_m4_v3(mat, &pt->x);
- brush->draw_angle = M_PI_4; /* 45 degrees */
- brush->draw_angle_factor = 1.0f;
+ pt->pressure = array[x + 3];
+ pt->strength = array[x + 4];
+ }
+}
- brush->draw_smoothfac = 1.0f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
+/* Create a new stroke, with pre-allocated data buffers */
+bGPDstroke *BKE_gpencil_add_stroke(bGPDframe *gpf, int mat_idx, int totpoints, short thickness)
+{
+ /* allocate memory for a new stroke */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
- /* Crayon brush */
- brush = BKE_gpencil_brush_addnew(ts, "Crayon", false);
- brush->thickness = 10.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 3.0f;
- brush->flag &= ~GP_BRUSH_USE_PRESSURE;
+ gps->thickness = thickness * 25;
+ gps->inittime = 0;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 0.140f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ /* enable recalculation flag by default */
+ gps->flag = GP_STROKE_RECALC_CACHES | GP_STROKE_3DSPACE;
- brush->draw_random_press = 0.0f;
+ gps->totpoints = totpoints;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights");
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ /* initialize triangle memory to dummy data */
+ gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation");
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
+ gps->mat_nr = mat_idx;
- brush->draw_smoothfac = 0.0f;
- brush->draw_smoothlvl = 1;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.5f;
+ /* add to frame */
+ BLI_addtail(&gpf->strokes, gps);
+ return gps;
}
-/* add a new gp-brush and make it the active */
-bGPDbrush *BKE_gpencil_brush_addnew(ToolSettings *ts, const char *name, bool setactive)
-{
- bGPDbrush *brush;
-
- /* check that list is ok */
- if (ts == NULL) {
- return NULL;
- }
-
- /* allocate memory and add to end of list */
- brush = MEM_callocN(sizeof(bGPDbrush), "bGPDbrush");
- /* add to datablock */
- BLI_addtail(&ts->gp_brushes, brush);
-
- /* set basic settings */
- brush->thickness = 3;
- brush->draw_smoothlvl = 1;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
- brush->draw_sensitivity = 1.0f;
- brush->draw_strength = 1.0f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- /* curves */
- brush->cur_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- brush->cur_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- brush->cur_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
-
- /* auto-name */
- BLI_strncpy(brush->info, name, sizeof(brush->info));
- BLI_uniquename(&ts->gp_brushes, brush, DATA_("GP_Brush"), '.', offsetof(bGPDbrush, info), sizeof(brush->info));
-
- /* make this one the active one */
- if (setactive) {
- BKE_gpencil_brush_setactive(ts, brush);
- }
-
- /* return brush */
- return brush;
-}
+/* ************************************************** */
+/* Data Duplication */
-/* add a new gp-palettecolor and make it the active */
-bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(bGPDpalette *palette, const char *name, bool setactive)
+/* make a copy of a given gpencil weights */
+void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_dst)
{
- bGPDpalettecolor *palcolor;
-
- /* check that list is ok */
- if (palette == NULL) {
- return NULL;
+ if (gps_src == NULL) {
+ return;
}
+ BLI_assert(gps_src->totpoints == gps_dst->totpoints);
- /* allocate memory and add to end of list */
- palcolor = MEM_callocN(sizeof(bGPDpalettecolor), "bGPDpalettecolor");
-
- /* add to datablock */
- BLI_addtail(&palette->colors, palcolor);
-
- /* set basic settings */
- palcolor->flag |= PC_COLOR_HQ_FILL;
- copy_v4_v4(palcolor->color, U.gpencil_new_layer_col);
- ARRAY_SET_ITEMS(palcolor->fill, 1.0f, 1.0f, 1.0f);
+ if ((gps_src->dvert == NULL) || (gps_dst->dvert == NULL)){
+ return;
+ }
- /* auto-name */
- BLI_strncpy(palcolor->info, name, sizeof(palcolor->info));
- BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
- sizeof(palcolor->info));
+ for (int i = 0; i < gps_src->totpoints; i++) {
+ MDeformVert *dvert_src = &gps_src->dvert[i];
+ MDeformVert *dvert_dst = &gps_dst->dvert[i];
+ if (dvert_src->totweight > 0) {
+ dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ }
+ else {
+ dvert_dst->dw = NULL;
+ }
- /* make this one the active one */
- if (setactive) {
- BKE_gpencil_palettecolor_setactive(palette, palcolor);
}
-
- /* return palette color */
- return palcolor;
}
-/* add a new gp-datablock */
-bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
+/* make a copy of a given gpencil stroke */
+bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src)
{
- bGPdata *gpd;
+ bGPDstroke *gps_dst = NULL;
- /* allocate memory for a new block */
- gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0);
+ gps_dst = MEM_dupallocN(gps_src);
+ gps_dst->prev = gps_dst->next = NULL;
- /* initial settings */
- gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND);
+ gps_dst->points = MEM_dupallocN(gps_src->points);
- /* for now, stick to view is also enabled by default
- * since this is more useful...
+ gps_dst->dvert = MEM_dupallocN(gps_src->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst);
+
+ /* 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.
*/
- gpd->flag |= GP_DATA_VIEWALIGN;
+ gps_dst->triangles = MEM_dupallocN(gps_dst->triangles);
+ /* gps_dst->flag |= GP_STROKE_RECALC_CACHES; */
- return gpd;
+ /* return new stroke */
+ return gps_dst;
}
-/* -------- Data Duplication ---------- */
-
/* make a copy of a given gpencil frame */
bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
{
- bGPDstroke *gps_dst;
+ bGPDstroke *gps_dst = NULL;
bGPDframe *gpf_dst;
/* error checking */
@@ -660,11 +605,8 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
/* copy strokes */
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, then adjust pointer to points too */
- gps_dst = MEM_dupallocN(gps_src);
- gps_dst->points = MEM_dupallocN(gps_src->points);
- gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
- gps_dst->flag |= GP_STROKE_RECALC_CACHES;
+ /* make copy of source stroke */
+ gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
BLI_addtail(&gpf_dst->strokes, gps_dst);
}
@@ -672,55 +614,24 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
return gpf_dst;
}
-/* make a copy of a given gpencil brush */
-bGPDbrush *BKE_gpencil_brush_duplicate(const bGPDbrush *brush_src)
+/* make a copy of strokes between gpencil frames */
+void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_dst)
{
- bGPDbrush *brush_dst;
-
+ bGPDstroke *gps_dst = NULL;
/* error checking */
- if (brush_src == NULL) {
- return NULL;
- }
-
- /* make a copy of source brush */
- brush_dst = MEM_dupallocN(brush_src);
- brush_dst->prev = brush_dst->next = NULL;
- /* make a copy of curves */
- brush_dst->cur_sensitivity = curvemapping_copy(brush_src->cur_sensitivity);
- brush_dst->cur_strength = curvemapping_copy(brush_src->cur_strength);
- brush_dst->cur_jitter = curvemapping_copy(brush_src->cur_jitter);
-
- /* return new brush */
- return brush_dst;
-}
-
-/* make a copy of a given gpencil palette */
-bGPDpalette *BKE_gpencil_palette_duplicate(const bGPDpalette *palette_src)
-{
- bGPDpalette *palette_dst;
- const bGPDpalettecolor *palcolor_src;
- bGPDpalettecolor *palcolord_dst;
-
- /* error checking */
- if (palette_src == NULL) {
- return NULL;
+ if ((gpf_src == NULL) || (gpf_dst == NULL)) {
+ return;
}
- /* make a copy of source palette */
- palette_dst = MEM_dupallocN(palette_src);
- palette_dst->prev = palette_dst->next = NULL;
-
- /* copy colors */
- BLI_listbase_clear(&palette_dst->colors);
- for (palcolor_src = palette_src->colors.first; palcolor_src; palcolor_src = palcolor_src->next) {
- /* make a copy of source */
- palcolord_dst = MEM_dupallocN(palcolor_src);
- BLI_addtail(&palette_dst->colors, palcolord_dst);
+ /* copy strokes */
+ 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);
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
}
-
- /* return new palette */
- return palette_dst;
}
+
/* make a copy of a given gpencil layer */
bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
{
@@ -736,6 +647,7 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
/* make a copy of source layer */
gpl_dst = MEM_dupallocN(gpl_src);
gpl_dst->prev = gpl_dst->next = NULL;
+ gpl_dst->runtime.derived_data = NULL;
/* copy frames */
BLI_listbase_clear(&gpl_dst->frames);
@@ -755,7 +667,7 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
/**
* Only copy internal data of GreasePencil ID from source to already allocated/initialized destination.
- * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ * You probably never want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
*
* WARNING! This function will not handle ID user count!
*
@@ -763,6 +675,14 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
*/
void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag))
{
+ /* cache data is not duplicated */
+ gpd_dst->runtime.batch_cache_data = NULL;
+
+ /* duplicate material array */
+ if (gpd_src->mat) {
+ gpd_dst->mat = MEM_dupallocN(gpd_src->mat);
+ }
+
/* copy layers */
BLI_listbase_clear(&gpd_dst->layers);
for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
@@ -771,45 +691,46 @@ void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata
BLI_addtail(&gpd_dst->layers, gpl_dst);
}
- /* copy palettes */
- BLI_listbase_clear(&gpd_dst->palettes);
- for (const bGPDpalette *palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) {
- bGPDpalette *palette_dst = BKE_gpencil_palette_duplicate(palette_src); /* TODO here too could add unused flags... */
- BLI_addtail(&gpd_dst->palettes, palette_dst);
- }
+}
+
+/* Standard API to make a copy of GP datablock, separate from copying its data */
+bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd)
+{
+ bGPdata *gpd_copy;
+ BKE_id_copy_ex(bmain, &gpd->id, (ID **)&gpd_copy, 0, false);
+ return gpd_copy;
}
/* make a copy of a given gpencil datablock */
+// XXX: Should this be deprecated?
bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
{
+ bGPdata *gpd_dst;
+
/* Yuck and super-uber-hyper yuck!!!
* Should be replaceable with a no-main copy (LIB_ID_COPY_NO_MAIN etc.), but not sure about it,
* so for now keep old code for that one. */
- if (internal_copy) {
- const bGPDlayer *gpl_src;
- bGPDlayer *gpl_dst;
- bGPdata *gpd_dst;
+ /* error checking */
+ if (gpd_src == NULL) {
+ return NULL;
+ }
+
+ if (internal_copy) {
/* make a straight copy for undo buffers used during stroke drawing */
gpd_dst = MEM_dupallocN(gpd_src);
-
- /* copy layers */
- BLI_listbase_clear(&gpd_dst->layers);
- for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
- /* make a copy of source layer and its data */
- gpl_dst = BKE_gpencil_layer_duplicate(gpl_src);
- BLI_addtail(&gpd_dst->layers, gpl_dst);
- }
-
- /* return new */
- return gpd_dst;
}
else {
BLI_assert(bmain != NULL);
- bGPdata *gpd_copy;
- BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_copy, 0, false);
- return gpd_copy;
+ BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_dst, 0, false);
+ gpd_dst->runtime.batch_cache_data = NULL;
}
+
+ /* Copy internal data (layers, etc.) */
+ BKE_gpencil_copy_data(bmain, gpd_dst, gpd_src, 0);
+
+ /* return new */
+ return gpd_dst;
}
void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
@@ -817,7 +738,8 @@ void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
BKE_id_make_local_generic(bmain, &gpd->id, true, lib_local);
}
-/* -------- GP-Stroke API --------- */
+/* ************************************************** */
+/* GP Stroke API */
/* ensure selection status of stroke is in sync with its points */
void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps)
@@ -842,7 +764,8 @@ void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps)
}
}
-/* -------- GP-Frame API ---------- */
+/* ************************************************** */
+/* GP Frame API */
/* delete the last stroke of the given frame */
void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
@@ -855,7 +778,13 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
return;
/* free the stroke and its data */
- MEM_freeN(gps->points);
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
MEM_freeN(gps->triangles);
BLI_freelinkN(&gpf->strokes, gps);
@@ -866,7 +795,8 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
}
}
-/* -------- GP-Layer API ---------- */
+/* ************************************************** */
+/* GP Layer API */
/* Check if the given layer is able to be edited or not */
bool gpencil_layer_is_editable(const bGPDlayer *gpl)
@@ -1048,8 +978,6 @@ bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf)
*/
if (gpl->actframe == gpf)
gpl->actframe = gpf->prev;
- else
- gpl->actframe = NULL;
/* free the frame and its data */
changed = BKE_gpencil_free_strokes(gpf);
@@ -1103,255 +1031,602 @@ void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
/* free layer */
BKE_gpencil_free_frames(gpl);
+
+ /* free icon providing preview of icon color */
+ BKE_icon_delete(gpl->runtime.icon_id);
+
+ /* free derived data */
+ BKE_gpencil_clear_derived(gpl);
+ if (gpl->runtime.derived_data) {
+ BLI_ghash_free(gpl->runtime.derived_data, NULL, NULL);
+ gpl->runtime.derived_data = NULL;
+ }
+
BLI_freelinkN(&gpd->layers, gpl);
}
-/* ************************************************** */
-/* get the active gp-brush for editing */
-bGPDbrush *BKE_gpencil_brush_getactive(ToolSettings *ts)
+Material *BKE_gpencil_get_material_from_brush(Brush *brush)
{
- bGPDbrush *brush;
+ Material *ma = NULL;
- /* error checking */
- if (ELEM(NULL, ts, ts->gp_brushes.first)) {
- return NULL;
+ if ((brush != NULL) && (brush->gpencil_settings != NULL) &&
+ (brush->gpencil_settings->material != NULL))
+ {
+ ma = brush->gpencil_settings->material;
}
- /* loop over brushes until found (assume only one active) */
- for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
- if (brush->flag & GP_BRUSH_ACTIVE) {
- return brush;
+ return ma;
+}
+
+/* Get active color, and add all default settings if we don't find anything */
+Material *BKE_gpencil_material_ensure(Main *bmain, Object *ob)
+{
+ Material *ma = NULL;
+
+ /* sanity checks */
+ if (ELEM(NULL, bmain, ob))
+ return NULL;
+
+ ma = give_current_material(ob, ob->actcol);
+ if (ma == NULL) {
+ if (ob->totcol == 0) {
+ BKE_object_material_slot_add(bmain, ob);
}
+ ma = BKE_material_add_gpencil(bmain, DATA_("Material"));
+ assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_EXISTING);
+ }
+ else if (ma->gp_style == NULL) {
+ BKE_material_init_gpencil_settings(ma);
}
- /* no active brush found */
- return NULL;
+ return ma;
}
-/* set the active gp-brush */
-void BKE_gpencil_brush_setactive(ToolSettings *ts, bGPDbrush *active)
+/* ************************************************** */
+/* GP Object - Boundbox Support */
+
+/**
+ * Get min/max coordinate bounds for single stroke
+ * \return Returns whether we found any selected points
+ */
+bool BKE_gpencil_stroke_minmax(
+ const bGPDstroke *gps, const bool use_select,
+ float r_min[3], float r_max[3])
{
- bGPDbrush *brush;
+ const bGPDspoint *pt;
+ int i;
+ bool changed = false;
- /* error checking */
- if (ELEM(NULL, ts, ts->gp_brushes.first, active)) {
- return;
- }
+ if (ELEM(NULL, gps, r_min, r_max))
+ return false;
- /* loop over brushes deactivating all */
- for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
- brush->flag &= ~GP_BRUSH_ACTIVE;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {
+ minmax_v3v3_v3(r_min, r_max, &pt->x);
+ changed = true;
+ }
}
-
- /* set as active one */
- active->flag |= GP_BRUSH_ACTIVE;
+ return changed;
}
-/* delete the active gp-brush */
-void BKE_gpencil_brush_delete(ToolSettings *ts, bGPDbrush *brush)
+/* get min/max bounds of all strokes in GP datablock */
+static void gpencil_minmax(bGPdata *gpd, float r_min[3], float r_max[3])
{
- /* error checking */
- if (ELEM(NULL, ts, brush)) {
+ INIT_MINMAX(r_min, r_max);
+
+ if (gpd == NULL)
return;
- }
- /* free curves */
- if (brush->cur_sensitivity) {
- curvemapping_free(brush->cur_sensitivity);
- }
- if (brush->cur_strength) {
- curvemapping_free(brush->cur_strength);
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *gpf = gpl->actframe;
+
+ if (gpf != NULL) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ BKE_gpencil_stroke_minmax(gps, false, r_min, r_max);
+ }
+ }
}
- if (brush->cur_jitter) {
- curvemapping_free(brush->cur_jitter);
+}
+
+/* compute center of bounding box */
+void BKE_gpencil_centroid_3D(bGPdata *gpd, float r_centroid[3])
+{
+ float min[3], max[3], tot[3];
+
+ gpencil_minmax(gpd, min, max);
+
+ add_v3_v3v3(tot, min, max);
+ mul_v3_v3fl(r_centroid, tot, 0.5f);
+}
+
+
+/* create bounding box values */
+static void boundbox_gpencil(Object *ob)
+{
+ BoundBox *bb;
+ bGPdata *gpd;
+ float min[3], max[3];
+
+ if (ob->bb == NULL) {
+ ob->bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
}
- /* free */
- BLI_freelinkN(&ts->gp_brushes, brush);
+ bb = ob->bb;
+ gpd = ob->data;
+
+ gpencil_minmax(gpd, min, max);
+ BKE_boundbox_init_from_minmax(bb, min, max);
+
+ bb->flag &= ~BOUNDBOX_DIRTY;
}
-/* ************************************************** */
-/* get the active gp-palette for editing */
-bGPDpalette *BKE_gpencil_palette_getactive(bGPdata *gpd)
+/* get bounding box */
+BoundBox *BKE_gpencil_boundbox_get(Object *ob)
{
- bGPDpalette *palette;
+ bGPdata *gpd;
- /* error checking */
- if (ELEM(NULL, gpd, gpd->palettes.first)) {
+ if (ELEM(NULL, ob, ob->data))
return NULL;
- }
- /* loop over palettes until found (assume only one active) */
- for (palette = gpd->palettes.first; palette; palette = palette->next) {
- if (palette->flag & PL_PALETTE_ACTIVE)
- return palette;
+ gpd = ob->data;
+ if ((ob->bb) && ((ob->bb->flag & BOUNDBOX_DIRTY) == 0) &&
+ ((gpd->flag & GP_DATA_CACHE_IS_DIRTY) == 0))
+ {
+ return ob->bb;
}
- /* no active palette found */
- return NULL;
+ boundbox_gpencil(ob);
+
+ return ob->bb;
}
-/* set the active gp-palette */
-void BKE_gpencil_palette_setactive(bGPdata *gpd, bGPDpalette *active)
-{
- bGPDpalette *palette;
+/* ************************************************** */
+/* Apply Transforms */
- /* error checking */
- if (ELEM(NULL, gpd, gpd->palettes.first, active)) {
+void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4])
+{
+ if (gpd == NULL)
return;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* FIXME: For now, we just skip parented layers.
+ * Otherwise, we have to update each frame to find
+ * the current parent position/effects.
+ */
+ if (gpl->parent) {
+ continue;
+ }
+
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
+ for (pt = gps->points, i = 0; i < gps->totpoints; pt++, i++) {
+ mul_m4_v3(mat, &pt->x);
+ }
+
+ /* TODO: Do we need to do this? distortion may mean we need to re-triangulate */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+ }
+ }
}
- /* loop over palettes deactivating all */
- for (palette = gpd->palettes.first; palette; palette = palette->next) {
- palette->flag &= ~PL_PALETTE_ACTIVE;
+}
+
+/* ************************************************** */
+/* GP Object - Vertex Groups */
+
+/* remove a vertex group */
+void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
+{
+ bGPdata *gpd = ob->data;
+ MDeformVert *dvert = NULL;
+ MDeformWeight *gpw = NULL;
+ const int def_nr = BLI_findindex(&ob->defbase, 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) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ dvert = &gps->dvert[i];
+ for (int i2 = 0; i2 < dvert->totweight; i2++) {
+ gpw = &dvert->dw[i2];
+ if (gpw->def_nr == def_nr) {
+ BKE_gpencil_vgroup_remove_point_weight(dvert, def_nr);
+ }
+ /* if index is greater, must be moved one back */
+ if (gpw->def_nr > def_nr) {
+ gpw->def_nr--;
+ }
+ }
+ }
+ }
+ }
+ }
}
- /* set as active one */
- active->flag |= PL_PALETTE_ACTIVE;
- /* force color recalc */
- BKE_gpencil_palette_change_strokes(gpd);
+ /* Remove the group */
+ BLI_freelinkN(&ob->defbase, defgroup);
}
-/* delete the active gp-palette */
-void BKE_gpencil_palette_delete(bGPdata *gpd, bGPDpalette *palette)
+/* add a new weight */
+MDeformWeight *BKE_gpencil_vgroup_add_point_weight(MDeformVert *dvert, int index, float weight)
{
- /* error checking */
- if (ELEM(NULL, gpd, palette)) {
- return;
+ MDeformWeight *new_gpw = NULL;
+ MDeformWeight *tmp_gpw;
+
+ /* need to verify if was used before to update */
+ for (int i = 0; i < dvert->totweight; i++) {
+ tmp_gpw = &dvert->dw[i];
+ if (tmp_gpw->def_nr == index) {
+ tmp_gpw->weight = weight;
+ return tmp_gpw;
+ }
+ }
+
+ dvert->totweight++;
+ if (dvert->totweight == 1) {
+ dvert->dw = MEM_callocN(sizeof(MDeformWeight), "gp_weight");
+ }
+ else {
+ dvert->dw = MEM_reallocN(dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
}
+ new_gpw = &dvert->dw[dvert->totweight - 1];
+ new_gpw->def_nr = index;
+ new_gpw->weight = weight;
- /* free colors */
- free_gpencil_colors(palette);
- BLI_freelinkN(&gpd->palettes, palette);
- /* force color recalc */
- BKE_gpencil_palette_change_strokes(gpd);
+ return new_gpw;
}
-/* Set all strokes to recalc the palette color */
-void BKE_gpencil_palette_change_strokes(bGPdata *gpd)
+/* return the weight if use index or -1*/
+float BKE_gpencil_vgroup_use_index(MDeformVert *dvert, int index)
{
- bGPDlayer *gpl;
- bGPDframe *gpf;
- bGPDstroke *gps;
+ MDeformWeight *gpw;
+ for (int i = 0; i < dvert->totweight; i++) {
+ gpw = &dvert->dw[i];
+ if (gpw->def_nr == index) {
+ return gpw->weight;
+ }
+ }
+ return -1.0f;
+}
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- gps->flag |= GP_STROKE_RECALC_COLOR;
- }
+/* add a new weight */
+bool BKE_gpencil_vgroup_remove_point_weight(MDeformVert *dvert, int index)
+{
+ int e = 0;
+
+ if (BKE_gpencil_vgroup_use_index(dvert, index) < 0.0f) {
+ return false;
+ }
+
+ /* if the array get empty, exit */
+ if (dvert->totweight == 1) {
+ dvert->totweight = 0;
+ MEM_SAFE_FREE(dvert->dw);
+ return true;
+ }
+
+ /* realloc weights */
+ MDeformWeight *tmp = MEM_dupallocN(dvert->dw);
+ MEM_SAFE_FREE(dvert->dw);
+ dvert->dw = MEM_callocN(sizeof(MDeformWeight) * dvert->totweight - 1, "gp_weights");
+
+ for (int x = 0; x < dvert->totweight; x++) {
+ MDeformWeight *gpw = &tmp[e];
+ MDeformWeight *final_gpw = &dvert->dw[e];
+ if (gpw->def_nr != index) {
+ final_gpw->def_nr = gpw->def_nr;
+ final_gpw->weight = gpw->weight;
+ e++;
}
}
+ MEM_SAFE_FREE(tmp);
+ dvert->totweight--;
+
+ return true;
}
-/* get the active gp-palettecolor for editing */
-bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(bGPDpalette *palette)
+/* ************************************************** */
+
+/**
+ * Apply smooth to stroke point
+ * \param gps Stroke to smooth
+ * \param i Point index
+ * \param inf Amount of smoothing to apply
+ */
+bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf)
{
- bGPDpalettecolor *palcolor;
+ bGPDspoint *pt = &gps->points[i];
+ // float pressure = 0.0f;
+ float sco[3] = { 0.0f };
- /* error checking */
- if (ELEM(NULL, palette, palette->colors.first)) {
- return NULL;
+ /* Do nothing if not enough points to smooth out */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
+
+ /* Only affect endpoints by a fraction of the normal strength,
+ * to prevent the stroke from shrinking too much
+ */
+ if ((i == 0) || (i == gps->totpoints - 1)) {
+ inf *= 0.1f;
}
- /* loop over colors until found (assume only one active) */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- if (palcolor->flag & PC_COLOR_ACTIVE) {
- return palcolor;
+ /* Compute smoothed coordinate by taking the ones nearby */
+ /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */
+ {
+ // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total)
+ const int steps = 2;
+ const float average_fac = 1.0f / (float)(steps * 2 + 1);
+ int step;
+
+ /* add the point itself */
+ madd_v3_v3fl(sco, &pt->x, average_fac);
+
+ /* n-steps before/after current point */
+ // XXX: review how the endpoints are treated by this algorithm
+ // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight
+ for (step = 1; step <= steps; step++) {
+ bGPDspoint *pt1, *pt2;
+ int before = i - step;
+ int after = i + step;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pt1 = &gps->points[before];
+ pt2 = &gps->points[after];
+
+ /* add both these points to the average-sum (s += p[i]/n) */
+ madd_v3_v3fl(sco, &pt1->x, average_fac);
+ madd_v3_v3fl(sco, &pt2->x, average_fac);
+
}
}
- /* no active color found */
- return NULL;
+ /* Based on influence factor, blend between original and optimal smoothed coordinate */
+ interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
+
+ return true;
}
-/* get the gp-palettecolor looking for name */
-bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(bGPDpalette *palette, char *name)
+
+/**
+ * Apply smooth for strength to stroke point */
+bool BKE_gpencil_smooth_stroke_strength(bGPDstroke *gps, int point_index, float influence)
{
- /* error checking */
- if (ELEM(NULL, palette, name)) {
- return NULL;
+ bGPDspoint *ptb = &gps->points[point_index];
+
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
}
- return BLI_findstring(&palette->colors, name, offsetof(bGPDpalettecolor, info));
+ /* Compute theoretical optimal value using distances */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the strength
+ * at the distance of point b
+ */
+ const float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength;
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->strength = (1.0f - influence) * ptb->strength + influence * optimal;
+
+ return true;
}
-/* Change color name in all strokes */
-void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char *newname)
+/**
+ * Apply smooth for thickness to stroke point (use pressure) */
+bool BKE_gpencil_smooth_stroke_thickness(bGPDstroke *gps, int point_index, float influence)
{
- bGPDlayer *gpl;
- bGPDframe *gpf;
- bGPDstroke *gps;
+ bGPDspoint *ptb = &gps->points[point_index];
- /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
- if (ELEM(NULL, gpd, oldname, newname))
- return;
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- if (STREQ(gps->colorname, oldname)) {
- BLI_strncpy(gps->colorname, newname, sizeof(gps->colorname));
- }
+ /* Compute theoretical optimal value using distances */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the pressure
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ float optimal = interpf(ptc->pressure, pta->pressure, fac);
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->pressure = interpf(optimal, ptb->pressure, influence);
+
+ return true;
+}
+
+/**
+* Apply smooth for UV rotation to stroke point (use pressure) */
+bool BKE_gpencil_smooth_stroke_uv(bGPDstroke *gps, int point_index, float influence)
+{
+ bGPDspoint *ptb = &gps->points[point_index];
+
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
+
+ /* Compute theoretical optimal value */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the pressure
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ float optimal = interpf(ptc->uv_rot, pta->uv_rot, fac);
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->uv_rot = interpf(optimal, ptb->uv_rot, influence);
+ CLAMP(ptb->uv_rot, -M_PI_2, M_PI_2);
+
+ return true;
+}
+
+/**
+ * Get range of selected frames in layer.
+ * Always the active frame is considered as selected, so if no more selected the range
+ * will be equal to the current active frame.
+ * \param gpl Layer
+ * \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)
+{
+ *r_initframe = gpl->actframe->framenum;
+ *r_endframe = gpl->actframe->framenum;
+
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ if (gpf->framenum < *r_initframe) {
+ *r_initframe = gpf->framenum;
+ }
+ if (gpf->framenum > *r_endframe) {
+ *r_endframe = gpf->framenum;
}
}
}
+}
+
+/**
+ * Get Falloff factor base on frame range
+ * \param gpf Frame
+ * \param actnum Number of active frame in layer
+ * \param f_init Number of first selected frame
+ * \param f_end Number of last selected frame
+ * \param cur_falloff Curve with falloff factors
+ */
+float BKE_gpencil_multiframe_falloff_calc(bGPDframe *gpf, int actnum, int f_init, int f_end, CurveMapping *cur_falloff)
+{
+ float fnum = 0.5f; /* default mid curve */
+ float value;
+
+ /* frames to the right of the active frame */
+ if (gpf->framenum < actnum) {
+ fnum = (float)(gpf->framenum - f_init) / (actnum - f_init);
+ fnum *= 0.5f;
+ value = curvemapping_evaluateF(cur_falloff, 0, fnum);
+ }
+ /* frames to the left of the active frame */
+ else if (gpf->framenum > actnum) {
+ fnum = (float)(gpf->framenum - actnum) / (f_end - actnum);
+ fnum *= 0.5f;
+ value = curvemapping_evaluateF(cur_falloff, 0, fnum + 0.5f);
+ }
+ else {
+ value = 1.0f;
+ }
+ return value;
}
-/* Delete all strokes of the color */
-void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name)
+/* remove strokes using a material */
+void BKE_gpencil_material_index_remove(bGPdata *gpd, int index)
{
- bGPDlayer *gpl;
- bGPDframe *gpf;
bGPDstroke *gps, *gpsn;
- /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
- if (ELEM(NULL, gpd, name))
- return;
-
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- if (STREQ(gps->colorname, name)) {
- if (gps->points) MEM_freeN(gps->points);
- if (gps->triangles) MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ if (gps->mat_nr == index) {
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ if (gps->triangles) MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+ }
+ else {
+ /* reassign strokes */
+ if (gps->mat_nr > index) {
+ gps->mat_nr--;
+ }
+ }
}
}
}
- }
-
}
-/* set the active gp-palettecolor */
-void BKE_gpencil_palettecolor_setactive(bGPDpalette *palette, bGPDpalettecolor *active)
+void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len)
{
- bGPDpalettecolor *palcolor;
-
- /* error checking */
- if (ELEM(NULL, palette, palette->colors.first, active)) {
- return;
+ const short remap_len_short = (short)remap_len;
+
+#define MAT_NR_REMAP(n) \
+ if (n < remap_len_short) { \
+ BLI_assert(n >= 0 && remap[n] < remap_len_short); \
+ n = remap[n]; \
+ } ((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) {
+ /* reassign strokes */
+ MAT_NR_REMAP(gps->mat_nr);
+ }
+ }
}
- /* loop over colors deactivating all */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag &= ~PC_COLOR_ACTIVE;
- }
+#undef MAT_NR_REMAP
- /* set as active one */
- active->flag |= PC_COLOR_ACTIVE;
}
-/* delete the active gp-palettecolor */
-void BKE_gpencil_palettecolor_delete(bGPDpalette *palette, bGPDpalettecolor *palcolor)
+/* statistics functions */
+void BKE_gpencil_stats_update(bGPdata *gpd)
{
- /* error checking */
- if (ELEM(NULL, palette, palcolor)) {
- return;
+ gpd->totlayer = 0;
+ gpd->totframe = 0;
+ gpd->totstroke = 0;
+ gpd->totpoint = 0;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpd->totlayer++;
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ gpd->totframe++;
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ gpd->totstroke++;
+ gpd->totpoint += gps->totpoints;
+ }
+ }
}
- /* free */
- BLI_freelinkN(&palette->colors, palcolor);
}
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
new file mode 100644
index 00000000000..2ba738902a0
--- /dev/null
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -0,0 +1,679 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/gpencil_modifier.c
+ * \ingroup bke
+ */
+
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
+
+#include "BLT_translation.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_global.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_gpencil.h"
+#include "BKE_lattice.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+
+static GpencilModifierTypeInfo *modifier_gpencil_types[NUM_GREASEPENCIL_MODIFIER_TYPES] = { NULL };
+
+/* *************************************************** */
+/* Geometry Utilities */
+
+/* calculate stroke normal using some points */
+void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
+{
+ if (gps->totpoints < 3) {
+ zero_v3(r_normal);
+ return;
+ }
+
+ bGPDspoint *points = gps->points;
+ int totpoints = gps->totpoints;
+
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+
+ float vec1[3];
+ float vec2[3];
+
+ /* initial vector (p0 -> p1) */
+ sub_v3_v3v3(vec1, &pt1->x, &pt0->x);
+
+ /* point vector at 3/4 */
+ sub_v3_v3v3(vec2, &pt3->x, &pt0->x);
+
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(r_normal, vec1, vec2);
+
+ /* Normalize vector */
+ normalize_v3(r_normal);
+}
+
+/* Get points of stroke always flat to view not affected by camera view or view position */
+static void gpencil_stroke_project_2d(const bGPDspoint *points, int totpoints, vec2f *points2d)
+{
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+
+ float locx[3];
+ float locy[3];
+ float loc3[3];
+ float normal[3];
+
+ /* local X axis (p0 -> p1) */
+ sub_v3_v3v3(locx, &pt1->x, &pt0->x);
+
+ /* point vector at 3/4 */
+ sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
+
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(normal, locx, loc3);
+
+ /* local Y axis (cross to normal/x axis) */
+ cross_v3_v3v3(locy, normal, locx);
+
+ /* Normalize vectors */
+ normalize_v3(locx);
+ normalize_v3(locy);
+
+ /* Get all points in local space */
+ for (int i = 0; i < totpoints; i++) {
+ const bGPDspoint *pt = &points[i];
+ float loc[3];
+
+ /* Get local space using first point as origin */
+ sub_v3_v3v3(loc, &pt->x, &pt0->x);
+
+ vec2f *point = &points2d[i];
+ point->x = dot_v3v3(loc, locx);
+ point->y = dot_v3v3(loc, locy);
+ }
+
+}
+
+/* Stroke Simplify ------------------------------------- */
+
+/* Reduce a series of points to a simplified version, but
+ * maintains the general shape of the series
+ *
+ * Ramer - Douglas - Peucker algorithm
+ * by http ://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
+ */
+static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon)
+{
+ vec2f *old_points2d = points2d;
+ int totpoints = gps->totpoints;
+ char *marked = NULL;
+ char work;
+
+ int start = 1;
+ int end = gps->totpoints - 2;
+
+ marked = MEM_callocN(totpoints, "GP marked array");
+ marked[start] = 1;
+ marked[end] = 1;
+
+ work = 1;
+ int totmarked = 0;
+ /* while still reducing */
+ while (work) {
+ int ls, le;
+ work = 0;
+
+ ls = start;
+ le = start + 1;
+
+ /* while not over interval */
+ while (ls < end) {
+ int max_i = 0;
+ float v1[2];
+ /* divided to get more control */
+ float max_dist = epsilon / 10.0f;
+
+ /* find the next marked point */
+ while (marked[le] == 0) {
+ le++;
+ }
+
+ /* perpendicular vector to ls-le */
+ v1[1] = old_points2d[le].x - old_points2d[ls].x;
+ v1[0] = old_points2d[ls].y - old_points2d[le].y;
+
+ for (int i = ls + 1; i < le; i++) {
+ float mul;
+ float dist;
+ float v2[2];
+
+ v2[0] = old_points2d[i].x - old_points2d[ls].x;
+ v2[1] = old_points2d[i].y - old_points2d[ls].y;
+
+ if (v2[0] == 0 && v2[1] == 0) {
+ continue;
+ }
+
+ mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]);
+
+ dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]);
+
+ if (dist > max_dist) {
+ max_dist = dist;
+ max_i = i;
+ }
+ }
+
+ if (max_i != 0) {
+ work = 1;
+ marked[max_i] = 1;
+ totmarked++;
+ }
+
+ ls = le;
+ le = ls + 1;
+ }
+ }
+
+ /* adding points marked */
+ bGPDspoint *old_points = MEM_dupallocN(gps->points);
+ MDeformVert *old_dvert = MEM_dupallocN(gps->dvert);
+
+ /* resize gps */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+
+ int j = 0;
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt_src = &old_points[i];
+ bGPDspoint *pt = &gps->points[j];
+
+ MDeformVert *dvert_src = &old_dvert[i];
+ MDeformVert *dvert = &gps->dvert[j];
+
+ if ((marked[i]) || (i == 0) || (i == totpoints - 1)) {
+ memcpy(pt, pt_src, sizeof(bGPDspoint));
+ memcpy(dvert, dvert_src, sizeof(MDeformVert));
+ j++;
+ }
+ else {
+ BKE_gpencil_free_point_weights(dvert_src);
+ }
+ }
+
+ gps->totpoints = j;
+
+ MEM_SAFE_FREE(old_points);
+ MEM_SAFE_FREE(old_dvert);
+ MEM_SAFE_FREE(marked);
+}
+
+/* Simplify stroke using Ramer-Douglas-Peucker algorithm */
+void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float factor)
+{
+ /* first create temp data and convert points to 2D */
+ vec2f *points2d = MEM_mallocN(sizeof(vec2f) * gps->totpoints, "GP Stroke temp 2d points");
+
+ gpencil_stroke_project_2d(gps->points, gps->totpoints, points2d);
+
+ gpencil_rdp_stroke(gps, points2d, factor);
+
+ MEM_SAFE_FREE(points2d);
+}
+
+/* Simplify alternate vertex of stroke except extrems */
+void BKE_gpencil_simplify_fixed(bGPDstroke *gps)
+{
+ if (gps->totpoints < 5) {
+ return;
+ }
+
+ /* save points */
+ bGPDspoint *old_points = MEM_dupallocN(gps->points);
+ MDeformVert *old_dvert = MEM_dupallocN(gps->dvert);
+
+ /* resize gps */
+ int newtot = (gps->totpoints - 2) / 2;
+ if (((gps->totpoints - 2) % 2) > 0) {
+ newtot++;
+ }
+ newtot += 2;
+
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+
+ int j = 0;
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt_src = &old_points[i];
+ bGPDspoint *pt = &gps->points[j];
+
+ MDeformVert *dvert_src = &old_dvert[i];
+ MDeformVert *dvert = &gps->dvert[j];
+
+ if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) {
+ memcpy(pt, pt_src, sizeof(bGPDspoint));
+ memcpy(dvert, dvert_src, sizeof(MDeformVert));
+ j++;
+ }
+ else {
+ BKE_gpencil_free_point_weights(dvert_src);
+ }
+ }
+
+ gps->totpoints = j;
+
+ MEM_SAFE_FREE(old_points);
+ MEM_SAFE_FREE(old_dvert);
+}
+
+/* *************************************************** */
+/* Modifier Utilities */
+
+/* Lattice Modifier ---------------------------------- */
+/* Usually, evaluation of the lattice modifier is self-contained.
+ * However, since GP's modifiers operate on a per-stroke basis,
+ * we need to these two extra functions that called before/after
+ * each loop over all the geometry being evaluated.
+ */
+
+/* init lattice deform data */
+void BKE_gpencil_lattice_init(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (md->type == eGpencilModifierType_Lattice) {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ Object *latob = NULL;
+
+ latob = mmd->object;
+ if ((!latob) || (latob->type != OB_LATTICE)) {
+ return;
+ }
+ if (mmd->cache_data) {
+ end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
+ }
+
+ /* init deform data */
+ mmd->cache_data = (struct LatticeDeformData *)init_latt_deform(latob, ob);
+ }
+ }
+}
+
+/* clear lattice deform data */
+void BKE_gpencil_lattice_clear(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (md->type == eGpencilModifierType_Lattice) {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ if ((mmd) && (mmd->cache_data)) {
+ end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
+ mmd->cache_data = NULL;
+ }
+ }
+ }
+}
+
+/* *************************************************** */
+/* Modifier Methods - Evaluation Loops, etc. */
+
+/* check if exist geometry modifiers */
+bool BKE_gpencil_has_geometry_modifiers(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti && mti->generateStrokes) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* apply stroke modifiers */
+void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *UNUSED(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)) {
+ continue;
+ }
+
+ if (mti && mti->deformStroke) {
+ mti->deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+/* 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)) {
+ continue;
+ }
+
+ if (mti->generateStrokes) {
+ mti->generateStrokes(md, depsgraph, ob, gpl, gpf);
+ }
+ }
+ }
+}
+
+/* *************************************************** */
+
+void BKE_gpencil_eval_geometry(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);
+ }
+
+ /* TODO: Move "derived_gpf" logic here from DRW_gpencil_populate_datablock()?
+ * This would be better than inventing our own logic for this stuff...
+ */
+
+ /* TODO: Move the following code to "BKE_gpencil_eval_done()" (marked as an exit node)
+ * later when there's more happening here. For now, let's just keep this in here to avoid
+ * needing to have one more node slowing down evaluation...
+ */
+ if (DEG_is_active(depsgraph)) {
+ bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
+
+ /* sync "actframe" changes back to main-db too,
+ * 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);
+ }
+ }
+}
+
+void BKE_gpencil_modifier_init(void)
+{
+ /* Initialize modifier types */
+ gpencil_modifier_type_init(modifier_gpencil_types); /* MOD_gpencil_util.c */
+}
+
+GpencilModifierData *BKE_gpencil_modifier_new(int type)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
+ GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name);
+
+ /* note, this name must be made unique later */
+ BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name));
+
+ md->type = type;
+ md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render | eGpencilModifierMode_Expanded;
+ md->flag = eGpencilModifierFlag_StaticOverride_Local;
+
+ if (mti->flags & eGpencilModifierTypeFlag_EnableInEditmode)
+ md->mode |= eGpencilModifierMode_Editmode;
+
+ if (mti->initData) mti->initData(md);
+
+ return md;
+}
+
+static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_min(id);
+ }
+}
+
+void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(md, NULL, (GreasePencilObjectWalkFunc)modifier_free_data_id_us_cb, NULL);
+ }
+ }
+
+ if (mti->freeData) mti->freeData(md);
+ if (md->error) MEM_freeN(md->error);
+
+ MEM_freeN(md);
+}
+
+void BKE_gpencil_modifier_free(GpencilModifierData *md)
+{
+ BKE_gpencil_modifier_free_ex(md, 0);
+}
+
+/* check unique name */
+bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd)
+{
+ if (modifiers && gmd) {
+ const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifierType_getInfo(gmd->type);
+ return BLI_uniquename(modifiers, gmd, DATA_(gmti->name), '.', offsetof(GpencilModifierData, name), sizeof(gmd->name));
+ }
+ return false;
+}
+
+bool BKE_gpencil_modifier_dependsOnTime(GpencilModifierData *md)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ return mti->dependsOnTime && mti->dependsOnTime(md);
+}
+
+const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type)
+{
+ /* type unsigned, no need to check < 0 */
+ if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') {
+ return modifier_gpencil_types[type];
+ }
+ else {
+ return NULL;
+ }
+}
+
+void BKE_gpencil_modifier_copyData_generic(const GpencilModifierData *md_src, GpencilModifierData *md_dst)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md_src->type);
+
+ /* md_dst may have alredy be fully initialized with some extra allocated data,
+ * we need to free it now to avoid memleak. */
+ if (mti->freeData) {
+ mti->freeData(md_dst);
+ }
+
+ const size_t data_size = sizeof(GpencilModifierData);
+ const char *md_src_data = ((const char *)md_src) + data_size;
+ char *md_dst_data = ((char *)md_dst) + data_size;
+ BLI_assert(data_size <= (size_t)mti->struct_size);
+ memcpy(md_dst_data, md_src_data, (size_t)mti->struct_size - data_size);
+}
+
+static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_plus(id);
+ }
+}
+
+void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md, GpencilModifierData *target, const int flag)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ target->mode = md->mode;
+ target->flag = md->flag;
+
+ if (mti->copyData) {
+ mti->copyData(md, target);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(target, NULL, gpencil_modifier_copy_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(target, NULL, (GreasePencilObjectWalkFunc)gpencil_modifier_copy_data_id_us_cb, NULL);
+ }
+ }
+}
+
+void BKE_gpencil_modifier_copyData(GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_ex(md, target, 0);
+}
+
+GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifierType type)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+
+ for (; md; md = md->next)
+ if (md->type == type)
+ break;
+
+ return md;
+}
+
+void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+
+ for (; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti->foreachIDLink) mti->foreachIDLink(md, ob, walk, userData);
+ else if (mti->foreachObjectLink) {
+ /* each Object can masquerade as an ID, so this should be OK */
+ GreasePencilObjectWalkFunc fp = (GreasePencilObjectWalkFunc)walk;
+ mti->foreachObjectLink(md, ob, fp, userData);
+ }
+ }
+}
+
+void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc walk, void *userData)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+
+ for (; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti->foreachTexLink)
+ mti->foreachTexLink(md, ob, walk, userData);
+ }
+}
+
+GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *name)
+{
+ return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name));
+}
+
+/* helper function for per-instance positioning */
+void BKE_gpencil_instance_modifier_instance_tfm(InstanceGpencilModifierData *mmd, const int elem_idx[3], float r_mat[4][4])
+{
+ float offset[3], rot[3], scale[3];
+ int ri = mmd->rnd[0];
+ float factor;
+
+ offset[0] = mmd->offset[0] * elem_idx[0];
+ offset[1] = mmd->offset[1] * elem_idx[1];
+ offset[2] = mmd->offset[2] * elem_idx[2];
+
+ /* rotation */
+ if (mmd->flag & GP_INSTANCE_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);
+ }
+
+ /* scale */
+ if (mmd->flag & GP_INSTANCE_RANDOM_SIZE) {
+ factor = mmd->rnd_size * mmd->rnd[ri];
+ mul_v3_v3fl(scale, mmd->scale, factor);
+ add_v3_v3(scale, mmd->scale);
+ }
+ else {
+ copy_v3_v3(scale, mmd->scale);
+ }
+
+ /* advance random index */
+ mmd->rnd[0]++;
+ if (mmd->rnd[0] > 19) {
+ mmd->rnd[0] = 1;
+ }
+
+ /* calculate matrix */
+ loc_eul_size_to_mat4(r_mat, offset, rot, scale);
+}
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index 1c2575dfa52..3a4bf53e22d 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -37,6 +37,8 @@
#include "MEM_guardedalloc.h"
+#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
@@ -45,7 +47,6 @@
#include "DNA_screen_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
-#include "DNA_brush_types.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -127,6 +128,9 @@ static void icon_free_data(int icon_id, Icon *icon)
else if (icon->obj_type == ICON_DATA_PREVIEW) {
((PreviewImage *)(icon->obj))->icon_id = 0;
}
+ else if (icon->obj_type == ICON_DATA_GPLAYER) {
+ ((bGPDlayer *)(icon->obj))->runtime.icon_id = 0;
+ }
else if (icon->obj_type == ICON_DATA_GEOM) {
((struct Icon_Geom *)(icon->obj))->icon_id = 0;
}
@@ -598,6 +602,44 @@ int BKE_icon_id_ensure(struct ID *id)
return icon_id_ensure_create_icon(id);
}
+
+static int icon_gplayer_color_ensure_create_icon(bGPDlayer *gpl)
+{
+ BLI_assert(BLI_thread_is_main());
+
+ /* NOTE: The color previews for GP Layers don't really need
+ * to be "rendered" to image per se (as it will just be a plain
+ * colored rectangle), we need to define icon data here so that
+ * we can store a pointer to the layer data in icon->obj.
+ */
+ Icon *icon = icon_create(gpl->runtime.icon_id, ICON_DATA_GPLAYER, gpl);
+ icon->flag = ICON_FLAG_MANAGED;
+
+ return gpl->runtime.icon_id;
+}
+
+int BKE_icon_gplayer_color_ensure(bGPDlayer *gpl)
+{
+ /* Never handle icons in non-main thread! */
+ BLI_assert(BLI_thread_is_main());
+
+ if (!gpl || G.background) {
+ return 0;
+ }
+
+ if (gpl->runtime.icon_id)
+ return gpl->runtime.icon_id;
+
+ gpl->runtime.icon_id = get_next_free_id();
+
+ if (!gpl->runtime.icon_id) {
+ printf("%s: Internal error - not enough IDs\n", __func__);
+ return 0;
+ }
+
+ return icon_gplayer_color_ensure_create_icon(gpl);
+}
+
/**
* Return icon id of given preview, or create new icon if not found.
*/
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 351214ed72b..1d70d9db1e9 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -1073,6 +1073,7 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[INDEX_ID_IP] = &(main->ipo);
lb[INDEX_ID_AC] = &(main->action); /* moved here to avoid problems when freeing with animato (aligorith) */
lb[INDEX_ID_KE] = &(main->key);
+ lb[INDEX_ID_PAL] = &(main->palettes); /* referenced by gpencil, so needs to be before that to avoid crashes */
lb[INDEX_ID_GD] = &(main->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */
lb[INDEX_ID_NT] = &(main->nodetree);
lb[INDEX_ID_IM] = &(main->image);
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index 93fdd3349bf..473dd787a69 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -417,7 +417,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
SEQ_END
}
- CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER);
for (CollectionObject *cob = scene->master_collection->gobject.first; cob; cob = cob->next) {
CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
@@ -478,6 +477,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
if (toolsett->uvsculpt) {
library_foreach_paint(&data, &toolsett->uvsculpt->paint);
}
+ if (toolsett->gp_paint) {
+ library_foreach_paint(&data, &toolsett->gp_paint->paint);
+ }
}
if (scene->rigidbody_world) {
@@ -641,6 +643,10 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
if (material->texpaintslot != NULL) {
CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP);
}
+ if (material->gp_style != NULL) {
+ CALLBACK_INVOKE(material->gp_style->sima, IDWALK_CB_USER);
+ CALLBACK_INVOKE(material->gp_style->ima, IDWALK_CB_USER);
+ }
break;
}
@@ -758,6 +764,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP);
CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP);
CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER);
+ if (brush->gpencil_settings) {
+ CALLBACK_INVOKE(brush->gpencil_settings->material, IDWALK_CB_USER);
+ }
library_foreach_mtex(&data, &brush->mtex);
library_foreach_mtex(&data, &brush->mask_mtex);
break;
@@ -941,10 +950,15 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
case ID_GD:
{
bGPdata *gpencil = (bGPdata *) id;
+ /* materials */
+ for (i = 0; i < gpencil->totcol; i++) {
+ CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER);
+ }
- for (bGPDlayer *gp_layer = gpencil->layers.first; gp_layer; gp_layer = gp_layer->next) {
- CALLBACK_INVOKE(gp_layer->parent, IDWALK_CB_NOP);
+ for (bGPDlayer *gplayer = gpencil->layers.first; gplayer != NULL; gplayer = gplayer->next) {
+ CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP);
}
+
break;
}
@@ -1072,7 +1086,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
return true;
#endif
case ID_BR:
- return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE);
+ return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE, ID_MA);
case ID_PA:
return ELEM(id_type_used, ID_OB, ID_GR, ID_TE);
case ID_MC:
@@ -1083,6 +1097,8 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
return (ELEM(id_type_used, ID_TE, ID_OB));
case ID_LP:
return ELEM(id_type_used, ID_IM);
+ case ID_GD:
+ return ELEM(id_type_used, ID_MA);
case ID_WS:
return ELEM(id_type_used, ID_SCR, ID_SCE);
case ID_IM:
@@ -1091,7 +1107,6 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_SO:
case ID_AR:
case ID_AC:
- case ID_GD:
case ID_WM:
case ID_PAL:
case ID_PC:
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 28d75811185..03ec26c07d0 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -43,6 +43,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_customdata_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_ID.h"
#include "DNA_meta_types.h"
#include "DNA_node_types.h"
@@ -58,6 +59,7 @@
#include "BKE_animsys.h"
#include "BKE_displist.h"
#include "BKE_global.h"
+#include "BKE_gpencil.h"
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_library.h"
@@ -103,10 +105,30 @@ void BKE_material_free(Material *ma)
MEM_SAFE_FREE(ma->texpaintslot);
+ MEM_SAFE_FREE(ma->gp_style);
+
BKE_icon_id_delete((ID *)ma);
BKE_previewimg_free(&ma->preview);
}
+void BKE_material_init_gpencil_settings(Material *ma)
+{
+ if ((ma) && (ma->gp_style == NULL)) {
+ ma->gp_style = MEM_callocN(sizeof(MaterialGPencilStyle), "Grease Pencil Material Settings");
+
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ /* set basic settings */
+ gp_style->stroke_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;
+ }
+}
+
void BKE_material_init(Material *ma)
{
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ma, id));
@@ -124,6 +146,7 @@ void BKE_material_init(Material *ma)
ma->preview = NULL;
ma->alpha_threshold = 0.5f;
+
}
Material *BKE_material_add(Main *bmain, const char *name)
@@ -137,6 +160,19 @@ Material *BKE_material_add(Main *bmain, const char *name)
return ma;
}
+Material *BKE_material_add_gpencil(Main *bmain, const char *name)
+{
+ Material *ma;
+
+ ma = BKE_material_add(bmain, name);
+
+ /* grease pencil settings */
+ BKE_material_init_gpencil_settings(ma);
+
+ return ma;
+}
+
+
/**
* Only copy internal data of Material ID from source to already allocated/initialized destination.
* You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
@@ -164,6 +200,10 @@ void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_sr
ma_dst->texpaintslot = MEM_dupallocN(ma_src->texpaintslot);
}
+ if (ma_src->gp_style != NULL) {
+ ma_dst->gp_style = MEM_dupallocN(ma_src->gp_style);
+ }
+
BLI_listbase_clear(&ma_dst->gpumaterial);
/* TODO Duplicate Engine Settings and set runtime to NULL */
@@ -199,6 +239,7 @@ Material *BKE_material_localize(Material *ma)
man->texpaintslot = NULL;
man->preview = NULL;
+ /* man->gp_style = NULL; */ /* XXX: We probably don't want to clear here, or else we may get problems with COW later? */
BLI_listbase_clear(&man->gpumaterial);
/* TODO Duplicate Engine Settings and set runtime to NULL */
@@ -218,6 +259,7 @@ Material ***give_matarar(Object *ob)
Mesh *me;
Curve *cu;
MetaBall *mb;
+ bGPdata *gpd;
if (ob->type == OB_MESH) {
me = ob->data;
@@ -231,6 +273,10 @@ Material ***give_matarar(Object *ob)
mb = ob->data;
return &(mb->mat);
}
+ else if (ob->type == OB_GPENCIL) {
+ gpd = ob->data;
+ return &(gpd->mat);
+ }
return NULL;
}
@@ -239,6 +285,7 @@ short *give_totcolp(Object *ob)
Mesh *me;
Curve *cu;
MetaBall *mb;
+ bGPdata *gpd;
if (ob->type == OB_MESH) {
me = ob->data;
@@ -252,6 +299,10 @@ short *give_totcolp(Object *ob)
mb = ob->data;
return &(mb->totcol);
}
+ else if (ob->type == OB_GPENCIL) {
+ gpd = ob->data;
+ return &(gpd->totcol);
+ }
return NULL;
}
@@ -286,6 +337,8 @@ short *give_totcolp_id(ID *id)
return &(((Curve *)id)->totcol);
case ID_MB:
return &(((MetaBall *)id)->totcol);
+ case ID_GD:
+ return &(((bGPdata *)id)->totcol);
default:
break;
}
@@ -307,6 +360,9 @@ static void material_data_index_remove_id(ID *id, short index)
case ID_MB:
/* meta-elems don't have materials atm */
break;
+ case ID_GD:
+ BKE_gpencil_material_index_remove((bGPdata *)id, index);
+ break;
default:
break;
}
@@ -487,6 +543,21 @@ Material *give_current_material(Object *ob, short act)
return ma;
}
+MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act)
+{
+ Material *ma = give_current_material(ob, act);
+ if (ma != NULL) {
+ if (ma->gp_style == NULL) {
+ BKE_material_init_gpencil_settings(ma);
+ }
+
+ return ma->gp_style;
+ }
+ else {
+ return NULL;
+ }
+}
+
Material *give_node_material(Material *ma)
{
if (ma && ma->use_nodes && ma->nodetree) {
@@ -727,6 +798,9 @@ void BKE_material_remap_object(Object *ob, const unsigned int *remap)
else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
BKE_curve_material_remap(ob->data, remap, ob->totcol);
}
+ if (ob->type == OB_GPENCIL) {
+ BKE_gpencil_material_remap(ob->data, remap, ob->totcol);
+ }
else {
/* add support for this object data! */
BLI_assert(matar == NULL);
@@ -924,7 +998,7 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
}
/* check indices from mesh */
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_GPENCIL)) {
material_data_index_remove_id((ID *)ob->data, actcol - 1);
if (ob->runtime.curve_cache) {
BKE_displist_free(&ob->runtime.curve_cache->disp);
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 21b5bb89f19..c88de006eba 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -41,6 +41,7 @@
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
@@ -53,6 +54,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_shader_fx_types.h"
#include "DNA_smoke_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
@@ -86,6 +88,7 @@
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_icons.h"
#include "BKE_key.h"
#include "BKE_lamp.h"
@@ -110,12 +113,14 @@
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
+#include "BKE_shader_fx.h"
#include "BKE_speaker.h"
#include "BKE_softbody.h"
#include "BKE_subsurf.h"
#include "BKE_material.h"
#include "BKE_camera.h"
#include "BKE_image.h"
+#include "BKE_gpencil.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -185,11 +190,15 @@ void BKE_object_free_curve_cache(Object *ob)
void BKE_object_free_modifiers(Object *ob, const int flag)
{
ModifierData *md;
+ GpencilModifierData *gp_md;
while ((md = BLI_pophead(&ob->modifiers))) {
modifier_free_ex(md, flag);
}
+ while ((gp_md = BLI_pophead(&ob->greasepencil_modifiers))) {
+ BKE_gpencil_modifier_free_ex(gp_md, flag);
+ }
/* particle modifiers were freed, so free the particlesystems as well */
BKE_object_free_particlesystems(ob);
@@ -200,6 +209,15 @@ void BKE_object_free_modifiers(Object *ob, const int flag)
BKE_object_free_derived_caches(ob);
}
+void BKE_object_free_shaderfx(Object *ob, const int flag)
+{
+ ShaderFxData *fx;
+
+ while ((fx = BLI_pophead(&ob->shader_fx))) {
+ BKE_shaderfx_free_ex(fx, flag);
+ }
+}
+
void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
{
/* reset functionality */
@@ -222,6 +240,29 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
}
}
+void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData *hmd)
+{
+ if (hmd->object == NULL) {
+ return;
+ }
+ /* reset functionality */
+ bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
+
+ if (hmd->subtarget[0] && pchan) {
+ float imat[4][4], mat[4][4];
+
+ /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
+ mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
+
+ invert_m4_m4(imat, mat);
+ mul_m4_m4m4(hmd->parentinv, imat, ob->obmat);
+ }
+ else {
+ invert_m4_m4(hmd->object->imat, hmd->object->obmat);
+ mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat);
+ }
+}
+
bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
{
const ModifierTypeInfo *mti;
@@ -428,6 +469,7 @@ void BKE_object_free(Object *ob)
/* BKE_<id>_free shall never touch to ID->us. Never ever. */
BKE_object_free_modifiers(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
+ BKE_object_free_shaderfx(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
MEM_SAFE_FREE(ob->mat);
MEM_SAFE_FREE(ob->matbits);
@@ -653,6 +695,7 @@ static const char *get_obdata_defname(int type)
case OB_ARMATURE: return DATA_("Armature");
case OB_SPEAKER: return DATA_("Speaker");
case OB_EMPTY: return DATA_("Empty");
+ case OB_GPENCIL: return DATA_("GPencil");
default:
printf("get_obdata_defname: Internal error, bad type: %d\n", type);
return DATA_("Empty");
@@ -677,6 +720,7 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
case OB_ARMATURE: return BKE_armature_add(bmain, name);
case OB_SPEAKER: return BKE_speaker_add(bmain, name);
case OB_LIGHTPROBE:return BKE_lightprobe_add(bmain, name);
+ case OB_GPENCIL: return BKE_gpencil_data_addnew(bmain, name);
case OB_EMPTY: return NULL;
default:
printf("%s: Internal error, bad type: %d\n", __func__, type);
@@ -810,7 +854,7 @@ Object *BKE_object_add(
/**
* Add a new object, using another one as a reference
*
- * /param ob_src object to use to determine the collections of the new object.
+ * \param ob_src object to use to determine the collections of the new object.
*/
Object *BKE_object_add_from(
Main *bmain, Scene *scene, ViewLayer *view_layer,
@@ -828,6 +872,41 @@ Object *BKE_object_add_from(
return ob;
}
+/**
+ * Add a new object, but assign the given datablock as the ob->data
+ * for the newly created object.
+ *
+ * \param data The datablock to assign as ob->data for the new object.
+ * This is assumed to be of the correct type.
+ * \param do_id_user If true, id_us_plus() will be called on data when
+ * assigning it to the object.
+ */
+Object *BKE_object_add_for_data(
+ Main *bmain, ViewLayer *view_layer,
+ int type, const char *name, ID *data, bool do_id_user)
+{
+ Object *ob;
+ Base *base;
+ LayerCollection *layer_collection;
+
+ /* same as object_add_common, except we don't create new ob->data */
+ ob = BKE_object_add_only_object(bmain, type, name);
+ ob->data = data;
+ if (do_id_user) id_us_plus(data);
+
+ BKE_view_layer_base_deselect_all(view_layer);
+ DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+
+ layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, ob);
+
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_select(view_layer, base);
+
+ return ob;
+}
+
+
void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag)
{
SoftBody *sb = ob_src->soft;
@@ -1153,6 +1232,8 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, const int flag)
{
ModifierData *md;
+ GpencilModifierData *gmd;
+ ShaderFxData *fx;
/* Do not copy runtime data. */
BKE_object_runtime_reset(ob_dst);
@@ -1179,6 +1260,24 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con
BLI_addtail(&ob_dst->modifiers, nmd);
}
+ BLI_listbase_clear(&ob_dst->greasepencil_modifiers);
+
+ for (gmd = ob_src->greasepencil_modifiers.first; gmd; gmd = gmd->next) {
+ GpencilModifierData *nmd = BKE_gpencil_modifier_new(gmd->type);
+ BLI_strncpy(nmd->name, gmd->name, sizeof(nmd->name));
+ BKE_gpencil_modifier_copyData_ex(gmd, nmd, flag_subdata);
+ BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
+ }
+
+ BLI_listbase_clear(&ob_dst->shader_fx);
+
+ for (fx = ob_src->shader_fx.first; fx; fx = fx->next) {
+ ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
+ BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
+ BKE_shaderfx_copyData_ex(fx, nfx, flag_subdata);
+ BLI_addtail(&ob_dst->shader_fx, nfx);
+ }
+
if (ob_src->pose) {
copy_object_pose(ob_dst, ob_src, flag_subdata);
/* backwards compat... non-armatures can get poses in older files? */
@@ -1210,6 +1309,10 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con
BLI_listbase_clear((ListBase *)&ob_dst->drawdata);
BLI_listbase_clear(&ob_dst->pc_ids);
+ /* grease pencil: clean derived data */
+ if (ob_dst->type == OB_GPENCIL)
+ BKE_gpencil_free_derived_frames(ob_dst->data);
+
ob_dst->avs = ob_src->avs;
ob_dst->mpath = animviz_copy_motionpath(ob_src->mpath);
@@ -1469,6 +1572,11 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size)
ob->empty_drawsize *= size;
break;
}
+ case OB_GPENCIL:
+ {
+ ob->empty_drawsize *= size;
+ break;
+ }
case OB_FONT:
{
Curve *cu = ob->data;
@@ -2452,7 +2560,7 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool us
float size[3];
copy_v3_v3(size, ob->size);
- if (ob->type == OB_EMPTY) {
+ if ((ob->type == OB_EMPTY) || (ob->type == OB_GPENCIL)) {
mul_v3_fl(size, ob->empty_drawsize);
}
@@ -3694,6 +3802,88 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
return false;
}
+bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
+{
+ if (BKE_gpencil_modifier_dependsOnTime(md)) {
+ return true;
+ }
+
+ /* Check whether modifier is animated. */
+ /* TODO (Aligorith): this should be handled as part of build_animdata() */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
+
+ char pattern[MAX_NAME + 32];
+ BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md->name);
+
+ /* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */
+ if (adt->action) {
+ for (fcu = (FCurve *)adt->action->curves.first;
+ fcu != NULL;
+ fcu = (FCurve *)fcu->next)
+ {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ /* This here allows modifier properties to get driven and still update properly
+ *
+ */
+ for (fcu = (FCurve *)adt->drivers.first;
+ fcu != NULL;
+ fcu = (FCurve *)fcu->next)
+ {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
+{
+ if (BKE_shaderfx_dependsOnTime(fx)) {
+ return true;
+ }
+
+ /* Check whether effect is animated. */
+ /* TODO (Aligorith): this should be handled as part of build_animdata() */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
+
+ char pattern[MAX_NAME + 32];
+ BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx->name);
+
+ /* action - check for F-Curves with paths containing string[' */
+ if (adt->action) {
+ for (fcu = (FCurve *)adt->action->curves.first;
+ fcu != NULL;
+ fcu = (FCurve *)fcu->next)
+ {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ /* This here allows properties to get driven and still update properly
+ *
+ */
+ for (fcu = (FCurve *)adt->drivers.first;
+ fcu != NULL;
+ fcu = (FCurve *)fcu->next)
+ {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* set "ignore cache" flag for all caches on this object */
static void object_cacheIgnoreClear(Object *ob, int state)
{
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index 5c9e53aaa56..a6b0e57e55c 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -53,6 +53,7 @@
#include "BKE_object.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_gpencil.h"
/** \name Misc helpers
* \{ */
@@ -402,12 +403,17 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
*/
void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
{
- if (BKE_object_is_in_editmode_vgroup(ob))
- object_defgroup_remove_edit_mode(ob, defgroup);
- else
- object_defgroup_remove_object_mode(ob, defgroup);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ BKE_gpencil_vgroup_remove(ob, defgroup);
+ }
+ else {
+ if (BKE_object_is_in_editmode_vgroup(ob))
+ object_defgroup_remove_edit_mode(ob, defgroup);
+ else
+ object_defgroup_remove_object_mode(ob, defgroup);
- BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ }
}
/**
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 3e72de3909f..3641df26496 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -62,6 +62,7 @@
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
+#include "BKE_gpencil.h"
#include "MEM_guardedalloc.h"
@@ -324,6 +325,9 @@ void BKE_object_eval_uber_data(Depsgraph *depsgraph,
case OB_MBALL:
BKE_mball_batch_cache_dirty(ob->data, BKE_MBALL_BATCH_DIRTY_ALL);
break;
+ case OB_GPENCIL:
+ BKE_gpencil_batch_cache_dirty(ob->data);
+ break;
}
}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 07aa21f44ff..cb26f7e9f3e 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -41,13 +41,19 @@
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
#include "DNA_space_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_workspace_types.h"
#include "BLI_bitmap.h"
+#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
#include "BLI_math_vector.h"
#include "BLI_listbase.h"
+#include "BLT_translation.h"
+
+#include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_deform.h"
@@ -55,6 +61,7 @@
#include "BKE_context.h"
#include "BKE_crazyspace.h"
#include "BKE_global.h"
+#include "BKE_gpencil.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
@@ -151,6 +158,8 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode)
return &ts->imapaint.paint;
case ePaintSculptUV:
return &ts->uvsculpt->paint;
+ case ePaintGpencil:
+ return &ts->gp_paint->paint;
case ePaintInvalid:
return NULL;
default:
@@ -176,6 +185,8 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer)
return &ts->wpaint->paint;
case OB_MODE_TEXTURE_PAINT:
return &ts->imapaint.paint;
+ case OB_MODE_GPENCIL_PAINT:
+ return &ts->gp_paint->paint;
case OB_MODE_EDIT:
if (ts->use_uv_sculpt)
return &ts->uvsculpt->paint;
@@ -430,13 +441,11 @@ PaletteColor *BKE_palette_color_add(Palette *palette)
return color;
}
-
bool BKE_palette_is_empty(const struct Palette *palette)
{
return BLI_listbase_is_empty(&palette->colors);
}
-
/* are we in vertex paint or weight pain face select mode? */
bool BKE_paint_select_face_test(Object *ob)
{
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index b50dc37af81..7085b515ec1 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -173,6 +173,10 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
ts->uvsculpt = MEM_dupallocN(ts->uvsculpt);
BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag);
}
+ if (ts->gp_paint) {
+ ts->gp_paint = MEM_dupallocN(ts->gp_paint);
+ BKE_paint_copy(&ts->gp_paint->paint, &ts->gp_paint->paint, flag);
+ }
BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag);
ts->imapaint.paintcursor = NULL;
@@ -180,15 +184,10 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
ts->particle.scene = NULL;
ts->particle.object = NULL;
- /* duplicate Grease Pencil Drawing Brushes */
- BLI_listbase_clear(&ts->gp_brushes);
- for (bGPDbrush *brush = toolsettings->gp_brushes.first; brush; brush = brush->next) {
- bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush);
- BLI_addtail(&ts->gp_brushes, newbrush);
- }
-
/* duplicate Grease Pencil interpolation curve */
ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
+ /* duplicate Grease Pencil multiframe fallof */
+ ts->gp_sculpt.cur_falloff = curvemapping_copy(ts->gp_sculpt.cur_falloff);
return ts;
}
@@ -213,16 +212,20 @@ void BKE_toolsettings_free(ToolSettings *toolsettings)
BKE_paint_free(&toolsettings->uvsculpt->paint);
MEM_freeN(toolsettings->uvsculpt);
}
+ if (toolsettings->gp_paint) {
+ BKE_paint_free(&toolsettings->gp_paint->paint);
+ MEM_freeN(toolsettings->gp_paint);
+ }
BKE_paint_free(&toolsettings->imapaint.paint);
- /* free Grease Pencil Drawing Brushes */
- BKE_gpencil_free_brushes(&toolsettings->gp_brushes);
- BLI_freelistN(&toolsettings->gp_brushes);
-
/* free Grease Pencil interpolation curve */
if (toolsettings->gp_interpolate.custom_ipo) {
curvemapping_free(toolsettings->gp_interpolate.custom_ipo);
}
+ /* free Grease Pencil multiframe falloff curve */
+ if (toolsettings->gp_sculpt.cur_falloff) {
+ curvemapping_free(toolsettings->gp_sculpt.cur_falloff);
+ }
MEM_freeN(toolsettings);
}
@@ -428,9 +431,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
}
/* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations
- * are done outside of blenkernel with ED_objects_single_users! */
+ * are done outside of blenkernel with ED_object_single_users! */
- /* camera */
+ /* camera */
if (ELEM(type, SCE_COPY_LINK_DATA, SCE_COPY_FULL)) {
ID_NEW_REMAP(sce_copy->camera);
}
@@ -683,6 +686,19 @@ void BKE_scene_init(Scene *sce)
sce->toolsettings->imapaint.normal_angle = 80;
sce->toolsettings->imapaint.seam_bleed = 2;
+ /* alloc grease pencil drawing brushes */
+ sce->toolsettings->gp_paint = MEM_callocN(sizeof(GpPaint), "GpPaint");
+
+ /* grease pencil multiframe falloff curve */
+ sce->toolsettings->gp_sculpt.cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ CurveMapping *gp_falloff_curve = sce->toolsettings->gp_sculpt.cur_falloff;
+ curvemapping_set_defaults(gp_falloff_curve, 1, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(gp_falloff_curve);
+ curvemap_reset(gp_falloff_curve->cm,
+ &gp_falloff_curve->clipr,
+ CURVE_PRESET_GAUSS,
+ CURVEMAP_SLOPE_POSITIVE);
+
sce->physics_settings.gravity[0] = 0.0f;
sce->physics_settings.gravity[1] = 0.0f;
sce->physics_settings.gravity[2] = -9.81f;
@@ -760,46 +776,65 @@ void BKE_scene_init(Scene *sce)
{
GP_BrushEdit_Settings *gset = &sce->toolsettings->gp_sculpt;
GP_EditBrush_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_EDITBRUSH_TYPE_SMOOTH];
gp_brush->size = 25;
gp_brush->strength = 0.3f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE | GP_EDITBRUSH_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_EDITBRUSH_TYPE_THICKNESS];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_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_EDITBRUSH_TYPE_STRENGTH];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_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_EDITBRUSH_TYPE_GRAB];
gp_brush->size = 50;
gp_brush->strength = 0.3f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_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_EDITBRUSH_TYPE_PUSH];
gp_brush->size = 25;
gp_brush->strength = 0.3f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_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_EDITBRUSH_TYPE_TWIST];
gp_brush->size = 50;
gp_brush->strength = 0.3f; // XXX?
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_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_EDITBRUSH_TYPE_PINCH];
gp_brush->size = 50;
gp_brush->strength = 0.5f; // XXX?
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_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_EDITBRUSH_TYPE_RANDOMIZE];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
}
/* GP Stroke Placement */
@@ -808,6 +843,10 @@ void BKE_scene_init(Scene *sce)
sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
+ /* Annotations */
+ sce->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR;
+ sce->toolsettings->annotate_thickness = 3;
+
sce->orientation_index_custom = -1;
/* Master Collection */
diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c
new file mode 100644
index 00000000000..c028c2184fd
--- /dev/null
+++ b/source/blender/blenkernel/intern/shader_fx.c
@@ -0,0 +1,245 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/shader_fx.c
+ * \ingroup bke
+ */
+
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_shader_fx_types.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_gpencil.h"
+#include "BKE_shader_fx.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "FX_shader_types.h"
+
+static ShaderFxTypeInfo *shader_fx_types[NUM_SHADER_FX_TYPES] = { NULL };
+
+/* *************************************************** */
+/* Methods - Evaluation Loops, etc. */
+
+/* check if exist grease pencil effects */
+bool BKE_shaderfx_has_gpencil(Object *ob)
+{
+ ShaderFxData *fx;
+ for (fx = ob->shader_fx.first; fx; fx = fx->next) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ if (fxi->type == eShaderFxType_GpencilType) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void BKE_shaderfx_init(void)
+{
+ /* Initialize shaders */
+ shaderfx_type_init(shader_fx_types); /* FX_shader_util.c */
+}
+
+ShaderFxData *BKE_shaderfx_new(int type)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type);
+ ShaderFxData *fx = MEM_callocN(fxi->struct_size, fxi->struct_name);
+
+ /* note, this name must be made unique later */
+ BLI_strncpy(fx->name, DATA_(fxi->name), sizeof(fx->name));
+
+ fx->type = type;
+ fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render | eShaderFxMode_Expanded;
+ fx->flag = eShaderFxFlag_StaticOverride_Local;
+
+ if (fxi->flags & eShaderFxTypeFlag_EnableInEditmode)
+ fx->mode |= eShaderFxMode_Editmode;
+
+ if (fxi->initData) fxi->initData(fx);
+
+ return fx;
+}
+
+static void shaderfx_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_min(id);
+ }
+}
+
+void BKE_shaderfx_free_ex(ShaderFxData *fx, const int flag)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (fxi->foreachIDLink) {
+ fxi->foreachIDLink(fx, NULL, shaderfx_free_data_id_us_cb, NULL);
+ }
+ else if (fxi->foreachObjectLink) {
+ fxi->foreachObjectLink(fx, NULL, (ShaderFxObjectWalkFunc)shaderfx_free_data_id_us_cb, NULL);
+ }
+ }
+
+ if (fxi->freeData) fxi->freeData(fx);
+ if (fx->error) MEM_freeN(fx->error);
+
+ MEM_freeN(fx);
+}
+
+void BKE_shaderfx_free(ShaderFxData *fx)
+{
+ BKE_shaderfx_free_ex(fx, 0);
+}
+
+/* check unique name */
+bool BKE_shaderfx_unique_name(ListBase *shaders, ShaderFxData *fx)
+{
+ if (shaders && fx) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ return BLI_uniquename(shaders, fx, DATA_(fxi->name), '.', offsetof(ShaderFxData, name), sizeof(fx->name));
+ }
+ return false;
+}
+
+bool BKE_shaderfx_dependsOnTime(ShaderFxData *fx)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ return fxi->dependsOnTime && fxi->dependsOnTime(fx);
+}
+
+const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type)
+{
+ /* type unsigned, no need to check < 0 */
+ if (type < NUM_SHADER_FX_TYPES && shader_fx_types[type]->name[0] != '\0') {
+ return shader_fx_types[type];
+ }
+ else {
+ return NULL;
+ }
+}
+
+void BKE_shaderfx_copyData_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx_src->type);
+
+ /* fx_dst may have alredy be fully initialized with some extra allocated data,
+ * we need to free it now to avoid memleak. */
+ if (fxi->freeData) {
+ fxi->freeData(fx_dst);
+ }
+
+ const size_t data_size = sizeof(ShaderFxData);
+ const char *fx_src_data = ((const char *)fx_src) + data_size;
+ char *fx_dst_data = ((char *)fx_dst) + data_size;
+ BLI_assert(data_size <= (size_t)fxi->struct_size);
+ memcpy(fx_dst_data, fx_src_data, (size_t)fxi->struct_size - data_size);
+}
+
+static void shaderfx_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_plus(id);
+ }
+}
+
+void BKE_shaderfx_copyData_ex(ShaderFxData *fx, ShaderFxData *target, const int flag)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ target->mode = fx->mode;
+ target->flag = fx->flag;
+
+ if (fxi->copyData) {
+ fxi->copyData(fx, target);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (fxi->foreachIDLink) {
+ fxi->foreachIDLink(target, NULL, shaderfx_copy_data_id_us_cb, NULL);
+ }
+ else if (fxi->foreachObjectLink) {
+ fxi->foreachObjectLink(target, NULL, (ShaderFxObjectWalkFunc)shaderfx_copy_data_id_us_cb, NULL);
+ }
+ }
+}
+
+void BKE_shaderfx_copyData(ShaderFxData *fx, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_ex(fx, target, 0);
+}
+
+ShaderFxData *BKE_shaderfx_findByType(Object *ob, ShaderFxType type)
+{
+ ShaderFxData *fx = ob->shader_fx.first;
+
+ for (; fx; fx = fx->next)
+ if (fx->type == type)
+ break;
+
+ return fx;
+}
+
+void BKE_shaderfx_foreachIDLink(Object *ob, ShaderFxIDWalkFunc walk, void *userData)
+{
+ ShaderFxData *fx = ob->shader_fx.first;
+
+ for (; fx; fx = fx->next) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ if (fxi->foreachIDLink) fxi->foreachIDLink(fx, ob, walk, userData);
+ else if (fxi->foreachObjectLink) {
+ /* each Object can masquerade as an ID, so this should be OK */
+ ShaderFxObjectWalkFunc fp = (ShaderFxObjectWalkFunc)walk;
+ fxi->foreachObjectLink(fx, ob, fp, userData);
+ }
+ }
+}
+
+ShaderFxData *BKE_shaderfx_findByName(Object *ob, const char *name)
+{
+ return BLI_findstring(&(ob->shader_fx), name, offsetof(ShaderFxData, name));
+}
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index ec16a6854c4..ef2ff10b5c6 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -78,6 +78,9 @@ MINLINE void zero_v3_int(int r[3]);
MINLINE void copy_v2_v2_int(int r[2], const int a[2]);
MINLINE void copy_v3_v3_int(int r[3], const int a[3]);
MINLINE void copy_v4_v4_int(int r[4], const int a[4]);
+/* int <-> float */
+MINLINE void copy_v2fl_v2i(float r[2], const int a[2]);
+MINLINE void round_v2i_v2fl(int r[2], const float a[2]);
/* double -> float */
MINLINE void copy_v2fl_v2db(float r[2], const double a[2]);
MINLINE void copy_v3fl_v3db(float r[3], const double a[3]);
diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h
index 612151b7ea2..f7dea562393 100644
--- a/source/blender/blenlib/BLI_rand.h
+++ b/source/blender/blenlib/BLI_rand.h
@@ -64,6 +64,9 @@ void BLI_rng_shuffle_array(struct RNG *rng, void *data, unsigned int elem
/** Note that skipping is as slow as generating n numbers! */
void BLI_rng_skip(struct RNG *rng, int n) ATTR_NONNULL(1);
+/* fill an array with random numbers */
+void BLI_array_frand(float *ar, int count, unsigned int seed);
+
/** Return a pseudo-random (hash) float from an integer value */
float BLI_hash_frand(unsigned int seed) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index 568448327bd..80b8a8d041c 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -578,6 +578,9 @@ void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
Link *link = NULL;
const char *id_iter;
+ if (id == NULL)
+ return NULL;
+
for (link = listbase->first; link; link = link->next) {
id_iter = ((const char *)link) + offset;
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 189b94a6f13..c4535eacefa 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -192,6 +192,19 @@ MINLINE void copy_v4_v4_int(int r[4], const int a[4])
r[3] = a[3];
}
+/* int <-> float */
+MINLINE void round_v2i_v2fl(int r[2], const float a[2])
+{
+ r[0] = (int)roundf(a[0]);
+ r[1] = (int)roundf(a[1]);
+}
+
+MINLINE void copy_v2fl_v2i(float r[2], const int a[2])
+{
+ r[0] = (float)a[0];
+ r[1] = (float)a[1];
+}
+
/* double -> float */
MINLINE void copy_v2fl_v2db(float r[2], const double a[2])
{
diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c
index 9e56ce6b2cf..8613a0ea6dd 100644
--- a/source/blender/blenlib/intern/rand.c
+++ b/source/blender/blenlib/intern/rand.c
@@ -265,6 +265,18 @@ void BLI_rng_skip(RNG *rng, int n)
/***/
+/* fill an array with random numbers */
+void BLI_array_frand(float *ar, int count, unsigned int seed)
+{
+ RNG rng;
+
+ BLI_rng_srandom(&rng, seed);
+
+ for (int i = 0; i < count; i++) {
+ ar[i] = BLI_rng_get_float(&rng);
+ }
+}
+
float BLI_hash_frand(unsigned int seed)
{
RNG rng;
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 816a527d829..293114c4b79 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -72,6 +72,8 @@
#include "DNA_genfile.h"
#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_shader_fx_types.h"
#include "DNA_ipo_types.h"
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
@@ -130,6 +132,8 @@
#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_global.h" // for G
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_layer.h"
#include "BKE_library.h" // for which_libbase
#include "BKE_library_idmap.h"
@@ -153,6 +157,7 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
+#include "BKE_shader_fx.h"
#include "BKE_outliner_treehash.h"
#include "BKE_sound.h"
#include "BKE_colortools.h"
@@ -266,6 +271,8 @@ static BHead *find_bhead_from_idname(FileData *fd, const char *idname);
#ifdef USE_COLLECTION_COMPAT_28
static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection *sc);
#endif
+static void direct_link_animdata(FileData *fd, AnimData *adt);
+static void lib_link_animdata(FileData *fd, ID *id, AnimData *adt);
/* this function ensures that reports are printed,
* in the case of libraray linking errors this is important!
@@ -2368,6 +2375,7 @@ static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap)
}
/* ************ READ Brush *************** */
+
/* library brush linking after fileread */
static void lib_link_brush(FileData *fd, Main *main)
{
@@ -2383,6 +2391,11 @@ static void lib_link_brush(FileData *fd, Main *main)
brush->toggle_brush = newlibadr(fd, brush->id.lib, brush->toggle_brush);
brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve);
+ /* link default grease pencil palette */
+ if (brush->gpencil_settings != NULL) {
+ brush->gpencil_settings->material = newlibadr_us(fd, brush->id.lib, brush->gpencil_settings->material);
+ }
+
brush->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -2394,6 +2407,7 @@ static void direct_link_brush(FileData *fd, Brush *brush)
/* fallof curve */
brush->curve = newdataadr(fd, brush->curve);
+
brush->gradient = newdataadr(fd, brush->gradient);
if (brush->curve)
@@ -2401,11 +2415,29 @@ static void direct_link_brush(FileData *fd, Brush *brush)
else
BKE_brush_curve_preset(brush, CURVE_PRESET_SHARP);
+ /* grease pencil */
+ brush->gpencil_settings = newdataadr(fd, brush->gpencil_settings);
+ if (brush->gpencil_settings != NULL) {
+ brush->gpencil_settings->curve_sensitivity = newdataadr(fd, brush->gpencil_settings->curve_sensitivity);
+ brush->gpencil_settings->curve_strength = newdataadr(fd, brush->gpencil_settings->curve_strength);
+ brush->gpencil_settings->curve_jitter = newdataadr(fd, brush->gpencil_settings->curve_jitter);
+
+ if (brush->gpencil_settings->curve_sensitivity)
+ direct_link_curvemapping(fd, brush->gpencil_settings->curve_sensitivity);
+
+ if (brush->gpencil_settings->curve_strength)
+ direct_link_curvemapping(fd, brush->gpencil_settings->curve_strength);
+
+ if (brush->gpencil_settings->curve_jitter)
+ direct_link_curvemapping(fd, brush->gpencil_settings->curve_jitter);
+ }
+
brush->preview = NULL;
brush->icon_imbuf = NULL;
}
/* ************ READ Palette *************** */
+
static void lib_link_palette(FileData *fd, Main *main)
{
/* only link ID pointers */
@@ -2420,6 +2452,7 @@ static void lib_link_palette(FileData *fd, Main *main)
static void direct_link_palette(FileData *fd, Palette *palette)
{
+
/* palette itself has been read */
link_list(fd, &palette->colors);
}
@@ -4147,6 +4180,17 @@ static void lib_link_material(FileData *fd, Main *main)
ma->nodetree->id.lib = ma->id.lib;
}
+ /* relink grease pencil settings */
+ if (ma->gp_style != NULL) {
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ if (gp_style->sima != NULL) {
+ gp_style->sima = newlibadr_us(fd, ma->id.lib, gp_style->sima);
+ }
+ if (gp_style->ima != NULL) {
+ gp_style->ima = newlibadr_us(fd, ma->id.lib, gp_style->ima);
+ }
+ }
+
ma->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -4167,6 +4211,8 @@ static void direct_link_material(FileData *fd, Material *ma)
ma->preview = direct_link_preview_image(fd, ma->preview);
BLI_listbase_clear(&ma->gpumaterial);
+
+ ma->gp_style = newdataadr(fd, ma->gp_style);
}
/* ************ READ PARTICLE SETTINGS ***************** */
@@ -4802,7 +4848,7 @@ static void direct_link_latt(FileData *fd, Lattice *lt)
/* ************ READ OBJECT ***************** */
-static void lib_link_modifiers__linkModifiers(
+static void lib_link_modifiers_common(
void *userData, Object *ob, ID **idpoin, int cb_flag)
{
FileData *fd = userData;
@@ -4812,9 +4858,10 @@ static void lib_link_modifiers__linkModifiers(
id_us_plus_no_lib(*idpoin);
}
}
+
static void lib_link_modifiers(FileData *fd, Object *ob)
{
- modifiers_foreachIDLink(ob, lib_link_modifiers__linkModifiers, fd);
+ modifiers_foreachIDLink(ob, lib_link_modifiers_common, fd);
/* If linking from a library, clear 'local' static override flag. */
if (ob->id.lib != NULL) {
@@ -4825,6 +4872,30 @@ static void lib_link_modifiers(FileData *fd, Object *ob)
}
+static void lib_link_gpencil_modifiers(FileData *fd, Object *ob)
+{
+ BKE_gpencil_modifiers_foreachIDLink(ob, lib_link_modifiers_common, fd);
+
+ /* If linking from a library, clear 'local' static override flag. */
+ if (ob->id.lib != NULL) {
+ for (GpencilModifierData *mod = ob->greasepencil_modifiers.first; mod != NULL; mod = mod->next) {
+ mod->flag &= ~eGpencilModifierFlag_StaticOverride_Local;
+ }
+ }
+}
+
+static void lib_link_shaderfxs(FileData *fd, Object *ob)
+{
+ BKE_shaderfx_foreachIDLink(ob, lib_link_modifiers_common, fd);
+
+ /* If linking from a library, clear 'local' static override flag. */
+ if (ob->id.lib != NULL) {
+ for (ShaderFxData *fx = ob->shader_fx.first; fx != NULL; fx = fx->next) {
+ fx->flag &= ~eShaderFxFlag_StaticOverride_Local;
+ }
+ }
+}
+
static void lib_link_object(FileData *fd, Main *main)
{
bool warn = false;
@@ -4961,6 +5032,8 @@ static void lib_link_object(FileData *fd, Main *main)
lib_link_particlesystems(fd, ob, &ob->id, &ob->particlesystem);
lib_link_modifiers(fd, ob);
+ lib_link_gpencil_modifiers(fd, ob);
+ lib_link_shaderfxs(fd, ob);
if (ob->rigidbody_constraint) {
ob->rigidbody_constraint->ob1 = newlibadr(fd, ob->id.lib, ob->rigidbody_constraint->ob1);
@@ -5356,6 +5429,61 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
}
}
+static void direct_link_gpencil_modifiers(FileData *fd, ListBase *lb)
+{
+ GpencilModifierData *md;
+
+ link_list(fd, lb);
+
+ for (md = lb->first; md; md = md->next) {
+ md->error = NULL;
+
+ /* if modifiers disappear, or for upward compatibility */
+ if (NULL == BKE_gpencil_modifierType_getInfo(md->type))
+ md->type = eModifierType_None;
+
+ if (md->type == eGpencilModifierType_Lattice) {
+ LatticeGpencilModifierData *gpmd = (LatticeGpencilModifierData*)md;
+ gpmd->cache_data = NULL;
+ }
+ else if (md->type == eGpencilModifierType_Hook) {
+ HookGpencilModifierData *hmd = (HookGpencilModifierData *)md;
+
+ hmd->curfalloff = newdataadr(fd, hmd->curfalloff);
+ if (hmd->curfalloff) {
+ direct_link_curvemapping(fd, hmd->curfalloff);
+ }
+ }
+ 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 */
+ curvemapping_initialize(gpmd->curve_thickness);
+ }
+ }
+
+ }
+}
+
+static void direct_link_shaderfxs(FileData *fd, ListBase *lb)
+{
+ ShaderFxData *fx;
+
+ link_list(fd, lb);
+
+ for (fx = lb->first; fx; fx = fx->next) {
+ fx->error = NULL;
+
+ /* if shader disappear, or for upward compatibility */
+ if (NULL == BKE_shaderfxType_getInfo(fx->type))
+ fx->type = eShaderFxType_None;
+
+ }
+}
+
static void direct_link_object(FileData *fd, Object *ob)
{
PartEff *paf;
@@ -5399,6 +5527,8 @@ static void direct_link_object(FileData *fd, Object *ob)
/* do it here, below old data gets converted */
direct_link_modifiers(fd, &ob->modifiers);
+ direct_link_gpencil_modifiers(fd, &ob->greasepencil_modifiers);
+ direct_link_shaderfxs(fd, &ob->shader_fx);
link_list(fd, &ob->effect);
paf= ob->effect.first;
@@ -5879,6 +6009,7 @@ static void lib_link_scene(FileData *fd, Main *main)
link_paint(fd, sce, &sce->toolsettings->wpaint->paint);
link_paint(fd, sce, &sce->toolsettings->imapaint.paint);
link_paint(fd, sce, &sce->toolsettings->uvsculpt->paint);
+ link_paint(fd, sce, &sce->toolsettings->gp_paint->paint);
if (sce->toolsettings->sculpt)
sce->toolsettings->sculpt->gravity_object =
@@ -6137,6 +6268,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
direct_link_paint_helper(fd, (Paint**)&sce->toolsettings->vpaint);
direct_link_paint_helper(fd, (Paint**)&sce->toolsettings->wpaint);
direct_link_paint_helper(fd, (Paint**)&sce->toolsettings->uvsculpt);
+ direct_link_paint_helper(fd, (Paint**)&sce->toolsettings->gp_paint);
direct_link_paint(fd, &sce->toolsettings->imapaint.paint);
@@ -6146,28 +6278,16 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->toolsettings->particle.object = NULL;
sce->toolsettings->gp_sculpt.paintcursor = NULL;
- /* relink grease pencil drawing brushes */
- link_list(fd, &sce->toolsettings->gp_brushes);
- for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
- brush->cur_sensitivity = newdataadr(fd, brush->cur_sensitivity);
- if (brush->cur_sensitivity) {
- direct_link_curvemapping(fd, brush->cur_sensitivity);
- }
- brush->cur_strength = newdataadr(fd, brush->cur_strength);
- if (brush->cur_strength) {
- direct_link_curvemapping(fd, brush->cur_strength);
- }
- brush->cur_jitter = newdataadr(fd, brush->cur_jitter);
- if (brush->cur_jitter) {
- direct_link_curvemapping(fd, brush->cur_jitter);
- }
- }
-
/* relink grease pencil interpolation curves */
sce->toolsettings->gp_interpolate.custom_ipo = newdataadr(fd, sce->toolsettings->gp_interpolate.custom_ipo);
if (sce->toolsettings->gp_interpolate.custom_ipo) {
direct_link_curvemapping(fd, sce->toolsettings->gp_interpolate.custom_ipo);
}
+ /* relink grease pencil multiframe falloff curve */
+ sce->toolsettings->gp_sculpt.cur_falloff = newdataadr(fd, sce->toolsettings->gp_sculpt.cur_falloff);
+ if (sce->toolsettings->gp_sculpt.cur_falloff) {
+ direct_link_curvemapping(fd, sce->toolsettings->gp_sculpt.cur_falloff);
+ }
}
if (sce->ed) {
@@ -6405,11 +6525,24 @@ static void direct_link_scene(FileData *fd, Scene *sce)
/* relink's grease pencil data's refs */
static void lib_link_gpencil(FileData *fd, Main *main)
{
+ /* Relink all datablock linked by GP datablock */
for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
if (gpd->id.tag & LIB_TAG_NEED_LINK) {
+ /* Layers */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* Layer -> Parent References */
+ gpl->parent = newlibadr(fd, gpd->id.lib, gpl->parent);
+ }
+
+ /* Datablock Stuff */
IDP_LibLinkProperty(gpd->id.properties, fd);
lib_link_animdata(fd, &gpd->id, gpd->adt);
+ /* materials */
+ for (int a = 0; a < gpd->totcol; a++) {
+ gpd->mat[a] = newlibadr_us(fd, gpd->id.lib, gpd->mat[a]);
+ }
+
gpd->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -6431,36 +6564,49 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
gpd->adt = newdataadr(fd, gpd->adt);
direct_link_animdata(fd, gpd->adt);
- /* relink palettes */
+ /* relink palettes (old palettes deprecated, only to convert old files) */
link_list(fd, &gpd->palettes);
- for (palette = gpd->palettes.first; palette; palette = palette->next) {
- link_list(fd, &palette->colors);
+ if (gpd->palettes.first != NULL) {
+ for (palette = gpd->palettes.first; palette; palette = palette->next) {
+ link_list(fd, &palette->colors);
+ }
}
+ /* clear drawing cache */
+ gpd->runtime.batch_cache_data = NULL;
+
+ /* materials */
+ gpd->mat = newdataadr(fd, gpd->mat);
+ test_pointer_array(fd, (void **)&gpd->mat);
+
/* relink layers */
link_list(fd, &gpd->layers);
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* parent */
- gpl->parent = newlibadr(fd, gpd->id.lib, gpl->parent);
/* relink frames */
link_list(fd, &gpl->frames);
+
gpl->actframe = newdataadr(fd, gpl->actframe);
+ gpl->runtime.derived_data = NULL;
+ gpl->runtime.icon_id = 0;
+
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
/* relink strokes (and their points) */
link_list(fd, &gpf->strokes);
for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* relink stroke points array */
gps->points = newdataadr(fd, gps->points);
+ /* relink weight data */
+ 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_CACHES;
- /* the color pointer is not saved, so need to be recalculated using the color name */
- gps->palcolor = NULL;
- gps->flag |= GP_STROKE_RECALC_COLOR;
}
}
}
@@ -8618,6 +8764,11 @@ static void do_versions_userdef(FileData *fd, BlendFileData *bfd)
user->walk_navigation.jump_height = 0.4f; /* m */
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;
+ }
}
static void do_versions(FileData *fd, Library *lib, Main *main)
@@ -8696,8 +8847,8 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_action(fd, main);
lib_link_vfont(fd, main);
lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */
- lib_link_brush(fd, main);
lib_link_palette(fd, main);
+ lib_link_brush(fd, main);
lib_link_paint_curve(fd, main);
lib_link_particlesettings(fd, main);
lib_link_movieclip(fd, main);
@@ -9434,6 +9585,9 @@ static void expand_brush(FileData *fd, Main *mainvar, Brush *brush)
expand_doit(fd, mainvar, brush->mask_mtex.tex);
expand_doit(fd, mainvar, brush->clone.image);
expand_doit(fd, mainvar, brush->paint_curve);
+ if (brush->gpencil_settings != NULL) {
+ expand_doit(fd, mainvar, brush->gpencil_settings->material);
+ }
}
static void expand_material(FileData *fd, Main *mainvar, Material *ma)
@@ -9445,6 +9599,12 @@ static void expand_material(FileData *fd, Main *mainvar, Material *ma)
if (ma->nodetree)
expand_nodetree(fd, mainvar, ma->nodetree);
+
+ if (ma->gp_style) {
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ expand_doit(fd, mainvar, gp_style->sima);
+ expand_doit(fd, mainvar, gp_style->ima);
+ }
}
static void expand_lamp(FileData *fd, Main *mainvar, Lamp *la)
@@ -9621,6 +9781,24 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
modifiers_foreachIDLink(ob, expand_object_expandModifiers, (void *)&data);
}
+ /* expand_object_expandModifier() */
+ if (ob->greasepencil_modifiers.first) {
+ struct { FileData *fd; Main *mainvar; } data;
+ data.fd = fd;
+ data.mainvar = mainvar;
+
+ BKE_gpencil_modifiers_foreachIDLink(ob, expand_object_expandModifiers, (void *)&data);
+ }
+
+ /* expand_object_expandShaderFx() */
+ if (ob->shader_fx.first) {
+ struct { FileData *fd; Main *mainvar; } data;
+ data.fd = fd;
+ data.mainvar = mainvar;
+
+ BKE_shaderfx_foreachIDLink(ob, expand_object_expandModifiers, (void *)&data);
+ }
+
expand_pose(fd, mainvar, ob->pose);
expand_doit(fd, mainvar, ob->poselib);
expand_constraints(fd, mainvar, &ob->constraints);
@@ -9899,8 +10077,18 @@ static void expand_linestyle(FileData *fd, Main *mainvar, FreestyleLineStyle *li
static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd)
{
- if (gpd->adt)
+ if (gpd->adt) {
expand_animdata(fd, mainvar, gpd->adt);
+ }
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ expand_doit(fd, mainvar, gpl->parent);
+ }
+
+ for (int a = 0; a < gpd->totcol; a++) {
+ expand_doit(fd, mainvar, gpd->mat[a]);
+ }
+
}
static void expand_workspace(FileData *fd, Main *mainvar, WorkSpace *workspace)
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 7a032dc3c90..f2f2e7d7881 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -1685,7 +1685,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
case SPACE_VIEW3D:
{
View3D *v3d = (View3D *)sl;
- v3d->flag2 |= V3D_SHOW_GPENCIL;
+ v3d->flag2 |= V3D_SHOW_ANNOTATION;
break;
}
case SPACE_SEQ:
@@ -1709,7 +1709,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
case SPACE_CLIP:
{
SpaceClip *sclip = (SpaceClip *)sl;
- sclip->flag |= SC_SHOW_GPENCIL;
+ sclip->flag |= SC_SHOW_ANNOTATION;
break;
}
}
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 7a106611e64..fadf332c850 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -76,6 +76,9 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "BLT_translation.h"
#include "BLO_readfile.h"
@@ -87,6 +90,64 @@
#include "MEM_guardedalloc.h"
+/* ************************************************** */
+/* GP Palettes API (Deprecated) */
+
+/* add a new gp-palette */
+static bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name)
+{
+ bGPDpalette *palette;
+
+ /* check that list is ok */
+ if (gpd == NULL) {
+ return NULL;
+ }
+
+ /* allocate memory and add to end of list */
+ palette = MEM_callocN(sizeof(bGPDpalette), "bGPDpalette");
+
+ /* add to datablock */
+ BLI_addtail(&gpd->palettes, palette);
+
+ /* set basic settings */
+ /* auto-name */
+ BLI_strncpy(palette->info, name, sizeof(palette->info));
+ BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info),
+ sizeof(palette->info));
+
+ /* return palette */
+ return palette;
+}
+
+/* add a new gp-palettecolor */
+static bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(bGPDpalette *palette, const char *name)
+{
+ bGPDpalettecolor *palcolor;
+
+ /* check that list is ok */
+ if (palette == NULL) {
+ return NULL;
+ }
+
+ /* allocate memory and add to end of list */
+ palcolor = MEM_callocN(sizeof(bGPDpalettecolor), "bGPDpalettecolor");
+
+ /* add to datablock */
+ BLI_addtail(&palette->colors, palcolor);
+
+ /* set basic settings */
+ copy_v4_v4(palcolor->color, U.gpencil_new_layer_col);
+ ARRAY_SET_ITEMS(palcolor->fill, 1.0f, 1.0f, 1.0f);
+
+ /* auto-name */
+ BLI_strncpy(palcolor->info, name, sizeof(palcolor->info));
+ BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
+ sizeof(palcolor->info));
+
+ /* return palette color */
+ return palcolor;
+}
+
/**
* Setup rotation stabilization from ancient single track spec.
* Former Version of 2D stabilization used a single tracking marker to determine the rotation
@@ -1344,8 +1405,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
ToolSettings *ts = scene->toolsettings;
/* initialize use position for sculpt brushes */
ts->gp_sculpt.flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
- /* initialize selected vertices alpha factor */
- ts->gp_sculpt.alpha = 1.0f;
/* new strength sculpt brush */
if (ts->gp_sculpt.brush[0].size >= 11) {
@@ -1358,25 +1417,16 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
}
}
- /* create a default grease pencil drawing brushes set */
- if (!BLI_listbase_is_empty(&bmain->gpencil)) {
- for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
- ToolSettings *ts = scene->toolsettings;
- if (BLI_listbase_is_empty(&ts->gp_brushes)) {
- BKE_gpencil_brush_init_presets(ts);
- }
- }
- }
/* Convert Grease Pencil to new palettes/brushes
* Loop all strokes and create the palette and all colors
*/
for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
if (BLI_listbase_is_empty(&gpd->palettes)) {
/* create palette */
- bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, "GP_Palette", true);
+ bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, "GP_Palette");
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* create color using layer name */
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_addnew(palette, gpl->info, true);
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_addnew(palette, gpl->info);
if (palcolor != NULL) {
/* set color attributes */
copy_v4_v4(palcolor->color, gpl->color);
@@ -1386,7 +1436,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (gpl->flag & GP_LAYER_LOCKED) palcolor->flag |= PC_COLOR_LOCKED;
if (gpl->flag & GP_LAYER_ONIONSKIN) palcolor->flag |= PC_COLOR_ONIONSKIN;
if (gpl->flag & GP_LAYER_VOLUMETRIC) palcolor->flag |= PC_COLOR_VOLUMETRIC;
- if (gpl->flag & GP_LAYER_HQ_FILL) palcolor->flag |= PC_COLOR_HQ_FILL;
/* set layer opacity to 1 */
gpl->opacity = 1.0f;
@@ -1399,8 +1448,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* set stroke to palette and force recalculation */
BLI_strncpy(gps->colorname, gpl->info, sizeof(gps->colorname));
- gps->palcolor = NULL;
- gps->flag |= GP_STROKE_RECALC_COLOR;
gps->thickness = gpl->thickness;
/* set alpha strength to 1 */
@@ -1410,13 +1457,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
-
- /* set thickness to 0 (now it is a factor to override stroke thickness) */
- gpl->thickness = 0.0f;
}
- /* set first color as active */
- if (palette->colors.first)
- BKE_gpencil_palettecolor_setactive(palette, palette->colors.first);
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 5b0a12a0b4c..7339f1977ff 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -54,16 +54,19 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "DNA_genfile.h"
+#include "DNA_gpencil_types.h"
#include "DNA_workspace_types.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_customdata.h"
+#include "BKE_colortools.h"
#include "BKE_freestyle.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
#include "BKE_layer.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
#include "BKE_pointcache.h"
@@ -73,6 +76,9 @@
#include "BKE_sequencer.h"
#include "BKE_studiolight.h"
#include "BKE_workspace.h"
+#include "BKE_gpencil.h"
+#include "BKE_paint.h"
+#include "BKE_object.h"
#include "BLO_readfile.h"
#include "readfile.h"
@@ -743,6 +749,7 @@ void do_versions_after_linking_280(Main *bmain)
}
}
#endif
+
}
/* NOTE: this version patch is intended for versions < 2.52.2, but was initially introduced in 2.27 already.
@@ -839,7 +846,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (ntree->type == NTREE_SHADER) {
for (bNode *node = ntree->nodes.first; node; node = node->next) {
if (node->type == 194 /* SH_NODE_EEVEE_METALLIC */ &&
- STREQ(node->idname, "ShaderNodeOutputMetallic"))
+ STREQ(node->idname, "ShaderNodeOutputMetallic"))
{
BLI_strncpy(node->idname, "ShaderNodeEeveeMetallic", sizeof(node->idname));
error |= NTREE_DOVERSION_NEED_OUTPUT;
@@ -851,14 +858,14 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
else if (node->type == 196 /* SH_NODE_OUTPUT_EEVEE_MATERIAL */ &&
- STREQ(node->idname, "ShaderNodeOutputEeveeMaterial"))
+ STREQ(node->idname, "ShaderNodeOutputEeveeMaterial"))
{
node->type = SH_NODE_OUTPUT_MATERIAL;
BLI_strncpy(node->idname, "ShaderNodeOutputMaterial", sizeof(node->idname));
}
else if (node->type == 194 /* SH_NODE_EEVEE_METALLIC */ &&
- STREQ(node->idname, "ShaderNodeEeveeMetallic"))
+ STREQ(node->idname, "ShaderNodeEeveeMetallic"))
{
node->type = SH_NODE_BSDF_PRINCIPLED;
BLI_strncpy(node->idname, "ShaderNodeBsdfPrincipled", sizeof(node->idname));
@@ -869,10 +876,10 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
} FOREACH_NODETREE_END
- if (error & NTREE_DOVERSION_NEED_OUTPUT) {
- BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console");
- printf("You need to connect Principled and Eevee Specular shader nodes to new material output nodes.\n");
- }
+ if (error & NTREE_DOVERSION_NEED_OUTPUT) {
+ BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console");
+ printf("You need to connect Principled and Eevee Specular shader nodes to new material output nodes.\n");
+ }
if (error & NTREE_DOVERSION_TRANSPARENCY_EMISSION) {
BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console");
@@ -896,6 +903,68 @@ 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_BrushEdit_Settings", "int", "weighttype")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ /* sculpt brushes */
+ GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt;
+ if (gset) {
+ gset->weighttype = GP_EDITBRUSH_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_EditBrush_Data *gp_brush;
+
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ ToolSettings *ts = scene->toolsettings;
+ /* sculpt brushes */
+ GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
+ for (int i = 0; i < TOT_GP_EDITBRUSH_TYPES; ++i) {
+ gp_brush = &gset->brush[i];
+ gp_brush->flag |= GP_EDITBRUSH_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->gpencil.first; gpd; gpd = gpd->id.next) {
+ ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f);
+ }
+ }
+
+ /* Init grease pencil pixel size factor */
+ if (!DNA_struct_elem_find(fd->filesdna, "bGPDdata", "int", "pixfactor")) {
+ for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
+ gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
+ }
+ }
+
+ /* Grease pencil multiframe falloff curve */
+ if (!DNA_struct_elem_find(fd->filesdna, "GP_BrushEdit_Settings", "CurveMapping", "cur_falloff")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ /* sculpt brushes */
+ GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt;
+ if ((gset) && (gset->cur_falloff == NULL)) {
+ gset->cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(gset->cur_falloff);
+ curvemap_reset(gset->cur_falloff->cm,
+ &gset->cur_falloff->clipr,
+ CURVE_PRESET_GAUSS,
+ CURVEMAP_SLOPE_POSITIVE);
+ }
+ }
+ }
+ }
}
#ifdef USE_COLLECTION_COMPAT_28
@@ -915,6 +984,26 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
#endif
+ 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]")) {
+ for (bScreen *screen = bmain->screen.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) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.gpencil_grid_scale = 1.0f; // Scale
+ v3d->overlay.gpencil_grid_lines = GP_DEFAULT_GRID_LINES; // NUmber of lines
+ v3d->overlay.gpencil_paper_opacity = 0.5f;
+ v3d->overlay.gpencil_grid_axis = V3D_GP_GRID_AXIS_Y;
+ v3d->overlay.gpencil_grid_opacity = 0.9f;
+ }
+ }
+ }
+ }
+ }
+ }
+
if (!MAIN_VERSION_ATLEAST(bmain, 280, 6)) {
if (DNA_struct_elem_find(fd->filesdna, "SpaceOops", "int", "filter") == false) {
bScreen *sc;
@@ -1017,6 +1106,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
tex->type = 0;
}
}
+
}
if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) {
@@ -1643,6 +1733,101 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
BKE_screen_view3d_shading_init(&scene->display.shading);
}
}
+ /* initialize grease pencil view data */
+ if (!DNA_struct_elem_find(fd->filesdna, "SpaceView3D", "float", "vertex_opacity")) {
+ for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->vertex_opacity = 1.0f;
+ v3d->flag3 |= V3D_GP_SHOW_EDIT_LINES;
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 22)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "annotate_v3d_align")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ scene->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR;
+ scene->toolsettings->annotate_thickness = 3;
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "bGPDlayer", "short", "line_change")) {
+ for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->line_change = gpl->thickness;
+ if ((gpl->thickness < 1) || (gpl->thickness > 10)) {
+ gpl->thickness = 3;
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_grid_scale")) {
+ for (bScreen *screen = bmain->screen.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) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.gpencil_grid_scale = 1.0f;
+ }
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_paper_opacity")) {
+ for (bScreen *screen = bmain->screen.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) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.gpencil_paper_opacity = 0.5f;
+ }
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_grid_opacity")) {
+ for (bScreen *screen = bmain->screen.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) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.gpencil_grid_opacity = 0.5f;
+ }
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "int", "gpencil_grid_axis")) {
+ for (bScreen *screen = bmain->screen.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) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.gpencil_grid_axis = V3D_GP_GRID_AXIS_Y;
+ }
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "int", "gpencil_grid_lines")) {
+ for (bScreen *screen = bmain->screen.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) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.gpencil_grid_lines = GP_DEFAULT_GRID_LINES;
+ }
+ }
+ }
+ }
+ }
+
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index bd7334516ca..a86986e2e09 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -170,46 +170,77 @@ void BLO_update_defaults_startup_blend(Main *bmain)
if (ts->gp_sculpt.brush[0].size == 0) {
GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
GP_EditBrush_Data *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);
+
+ /* default sculpt brush */
+ gset->brushtype = GP_EDITBRUSH_TYPE_PUSH;
+ /* default weight paint brush */
+ gset->weighttype = GP_EDITBRUSH_TYPE_WEIGHT;
brush = &gset->brush[GP_EDITBRUSH_TYPE_SMOOTH];
brush->size = 25;
brush->strength = 0.3f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(brush->curcolor_add, curcolor_add);
+ copy_v3_v3(brush->curcolor_sub, curcolor_sub);
brush = &gset->brush[GP_EDITBRUSH_TYPE_THICKNESS];
brush->size = 25;
brush->strength = 0.5f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(brush->curcolor_add, curcolor_add);
+ copy_v3_v3(brush->curcolor_sub, curcolor_sub);
brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH];
brush->size = 25;
brush->strength = 0.5f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(brush->curcolor_add, curcolor_add);
+ copy_v3_v3(brush->curcolor_sub, curcolor_sub);
brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
brush->size = 50;
brush->strength = 0.3f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(brush->curcolor_add, curcolor_add);
+ copy_v3_v3(brush->curcolor_sub, curcolor_sub);
brush = &gset->brush[GP_EDITBRUSH_TYPE_PUSH];
brush->size = 25;
brush->strength = 0.3f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(brush->curcolor_add, curcolor_add);
+ copy_v3_v3(brush->curcolor_sub, curcolor_sub);
brush = &gset->brush[GP_EDITBRUSH_TYPE_TWIST];
brush->size = 50;
brush->strength = 0.3f; // XXX?
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(brush->curcolor_add, curcolor_add);
+ copy_v3_v3(brush->curcolor_sub, curcolor_sub);
brush = &gset->brush[GP_EDITBRUSH_TYPE_PINCH];
brush->size = 50;
brush->strength = 0.5f; // XXX?
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(brush->curcolor_add, curcolor_add);
+ copy_v3_v3(brush->curcolor_sub, curcolor_sub);
brush = &gset->brush[GP_EDITBRUSH_TYPE_RANDOMIZE];
brush->size = 25;
brush->strength = 0.5f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(brush->curcolor_add, curcolor_add);
+ copy_v3_v3(brush->curcolor_sub, curcolor_sub);
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_WEIGHT];
+ brush->size = 25;
+ brush->strength = 0.5f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(brush->curcolor_add, curcolor_add);
+ copy_v3_v3(brush->curcolor_sub, curcolor_sub);
}
ts->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
@@ -217,6 +248,9 @@ void BLO_update_defaults_startup_blend(Main *bmain)
ts->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
ts->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
+ ts->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR;
+ ts->annotate_thickness = 3;
+
ParticleEditSettings *pset = &ts->particle;
for (int a = 0; a < ARRAY_SIZE(pset->brush); a++) {
pset->brush[a].strength = 0.5f;
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 503f8b44ec3..3883e024ab7 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -118,6 +118,8 @@
#include "DNA_genfile.h"
#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_shader_fx_types.h"
#include "DNA_fileglobal_types.h"
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
@@ -165,6 +167,7 @@
#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_global.h" // for G
+#include "BKE_gpencil_modifier.h"
#include "BKE_idcode.h"
#include "BKE_layer.h"
#include "BKE_library.h" // for set_listbasepointers
@@ -173,6 +176,7 @@
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_sequencer.h"
+#include "BKE_shader_fx.h"
#include "BKE_subsurf.h"
#include "BKE_modifier.h"
#include "BKE_fcurve.h"
@@ -1788,6 +1792,57 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
}
}
+static void write_gpencil_modifiers(WriteData *wd, ListBase *modbase)
+{
+ GpencilModifierData *md;
+
+ if (modbase == NULL) {
+ return;
+ }
+
+ for (md = modbase->first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ if (mti == NULL) {
+ return;
+ }
+
+ writestruct_id(wd, DATA, mti->struct_name, 1, md);
+
+ if (md->type == eGpencilModifierType_Thick) {
+ ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
+
+ if (gpmd->curve_thickness) {
+ write_curvemapping(wd, gpmd->curve_thickness);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Hook) {
+ HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md;
+
+ if (gpmd->curfalloff) {
+ write_curvemapping(wd, gpmd->curfalloff);
+ }
+ }
+ }
+}
+
+static void write_shaderfxs(WriteData *wd, ListBase *fxbase)
+{
+ ShaderFxData *fx;
+
+ if (fxbase == NULL) {
+ return;
+ }
+
+ for (fx = fxbase->first; fx; fx = fx->next) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ if (fxi == NULL) {
+ return;
+ }
+
+ writestruct_id(wd, DATA, fxi->struct_name, 1, fx);
+ }
+}
+
static void write_object(WriteData *wd, Object *ob)
{
if (ob->id.us > 0 || wd->use_memfile) {
@@ -1842,6 +1897,8 @@ static void write_object(WriteData *wd, Object *ob)
write_particlesystems(wd, &ob->particlesystem);
write_modifiers(wd, &ob->modifiers);
+ write_gpencil_modifiers(wd, &ob->greasepencil_modifiers);
+ write_shaderfxs(wd, &ob->shader_fx);
writelist(wd, DATA, LinkData, &ob->pc_ids);
writelist(wd, DATA, LodLevel, &ob->lodlevels);
@@ -2260,6 +2317,11 @@ static void write_material(WriteData *wd, Material *ma)
}
write_previews(wd, ma->preview);
+
+ /* grease pencil settings */
+ if (ma->gp_style) {
+ writestruct(wd, DATA, MaterialGPencilStyle, 1, ma->gp_style);
+ }
}
}
@@ -2463,24 +2525,18 @@ static void write_scene(WriteData *wd, Scene *sce)
writestruct(wd, DATA, UvSculpt, 1, tos->uvsculpt);
write_paint(wd, &tos->uvsculpt->paint);
}
- /* write grease-pencil drawing brushes to file */
- writelist(wd, DATA, bGPDbrush, &tos->gp_brushes);
- for (bGPDbrush *brush = tos->gp_brushes.first; brush; brush = brush->next) {
- if (brush->cur_sensitivity) {
- write_curvemapping(wd, brush->cur_sensitivity);
- }
- if (brush->cur_strength) {
- write_curvemapping(wd, brush->cur_strength);
- }
- if (brush->cur_jitter) {
- write_curvemapping(wd, brush->cur_jitter);
- }
+ if (tos->gp_paint) {
+ writestruct(wd, DATA, GpPaint, 1, tos->gp_paint);
+ write_paint(wd, &tos->gp_paint->paint);
}
/* write grease-pencil custom ipo curve to file */
if (tos->gp_interpolate.custom_ipo) {
write_curvemapping(wd, tos->gp_interpolate.custom_ipo);
}
-
+ /* write grease-pencil multiframe falloff curve to file */
+ if (tos->gp_sculpt.cur_falloff) {
+ write_curvemapping(wd, tos->gp_sculpt.cur_falloff);
+ }
write_paint(wd, &tos->imapaint.paint);
@@ -2654,6 +2710,8 @@ static void write_gpencil(WriteData *wd, bGPdata *gpd)
write_animdata(wd, gpd->adt);
}
+ writedata(wd, DATA, sizeof(void *) * gpd->totcol, gpd->mat);
+
/* write grease-pencil layers to file */
writelist(wd, DATA, bGPDlayer, &gpd->layers);
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
@@ -2664,15 +2722,10 @@ static void write_gpencil(WriteData *wd, bGPdata *gpd)
writelist(wd, DATA, bGPDstroke, &gpf->strokes);
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
writestruct(wd, DATA, bGPDspoint, gps->totpoints, gps->points);
+ write_dverts(wd, gps->totpoints, gps->dvert);
}
}
}
-
- /* write grease-pencil palettes */
- writelist(wd, DATA, bGPDpalette, &gpd->palettes);
- for (bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
- writelist(wd, DATA, bGPDpalettecolor, &palette->colors);
- }
}
}
@@ -3159,6 +3212,20 @@ static void write_brush(WriteData *wd, Brush *brush)
if (brush->curve) {
write_curvemapping(wd, brush->curve);
}
+
+ if (brush->gpencil_settings) {
+ writestruct(wd, DATA, BrushGpencilSettings, 1, brush->gpencil_settings);
+
+ if (brush->gpencil_settings->curve_sensitivity) {
+ write_curvemapping(wd, brush->gpencil_settings->curve_sensitivity);
+ }
+ if (brush->gpencil_settings->curve_strength) {
+ write_curvemapping(wd, brush->gpencil_settings->curve_strength);
+ }
+ if (brush->gpencil_settings->curve_jitter) {
+ write_curvemapping(wd, brush->gpencil_settings->curve_jitter);
+ }
+ }
if (brush->gradient) {
writestruct(wd, DATA, ColorBand, 1, brush->gradient);
}
diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp
index 47d8f4f52bb..248c780102c 100644
--- a/source/blender/collada/SceneExporter.cpp
+++ b/source/blender/collada/SceneExporter.cpp
@@ -69,6 +69,7 @@ void SceneExporter::exportHierarchy(bContext *C, Depsgraph *depsgraph, Scene *sc
case OB_CAMERA:
case OB_LAMP:
case OB_EMPTY:
+ case OB_GPENCIL:
case OB_ARMATURE:
base_objects.push_back(ob);
break;
@@ -122,6 +123,7 @@ void SceneExporter::writeNodes(bContext *C, Depsgraph *depsgraph, Object *ob, Sc
case OB_CAMERA:
case OB_LAMP:
case OB_EMPTY:
+ case OB_GPENCIL:
case OB_ARMATURE:
if (bc_is_marked(cob))
child_objects.push_back(cob);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 1b68a73bbd7..e20b589bf22 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -77,6 +77,8 @@ extern "C" {
#include "BKE_curve.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_idcode.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
@@ -93,6 +95,7 @@ extern "C" {
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
+#include "BKE_shader_fx.h"
#include "BKE_sound.h"
#include "BKE_tracking.h"
#include "BKE_world.h"
@@ -514,6 +517,18 @@ void DepsgraphNodeBuilder::build_object(int base_index,
data.builder = this;
modifiers_foreachIDLink(object, modifier_walk, &data);
}
+ /* Grease Pencil Modifiers. */
+ if (object->greasepencil_modifiers.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data);
+ }
+ /* Shadr FX. */
+ if (object->shader_fx.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ BKE_shaderfx_foreachIDLink(object, modifier_walk, &data);
+ }
/* Constraints. */
if (object->constraints.first != NULL) {
BuilderWalkUserData data;
@@ -538,10 +553,6 @@ void DepsgraphNodeBuilder::build_object(int base_index,
if (object->particlesystem.first != NULL) {
build_particles(object);
}
- /* Grease pencil. */
- if (object->gpd != NULL) {
- build_gpencil(object->gpd);
- }
/* Proxy object to copy from. */
if (object->proxy_from != NULL) {
build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY);
@@ -592,6 +603,7 @@ void DepsgraphNodeBuilder::build_object_data(Object *object)
case OB_SURF:
case OB_MBALL:
case OB_LATTICE:
+ case OB_GPENCIL:
build_object_data_geometry(object);
/* TODO(sergey): Only for until we support granular
* update of curves.
@@ -1213,6 +1225,20 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata)
op_node->set_as_entry();
break;
}
+
+ case ID_GD:
+ {
+ /* GPencil evaluation operations. */
+ op_node = add_operation_node(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ function_bind(BKE_gpencil_eval_geometry,
+ _1,
+ (bGPdata *)obdata_cow),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ op_node->set_as_entry();
+ break;
+ }
default:
BLI_assert(!"Should not happen");
break;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
index f1db05b7220..3d7b2d6d232 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
@@ -134,10 +134,6 @@ void DepsgraphNodeBuilder::build_view_layer(
if (scene->nodetree != NULL) {
build_compositor(scene);
}
- /* Grease pencil. */
- if (scene->gpd != NULL) {
- build_gpencil(scene->gpd);
- }
/* Cache file. */
LISTBASE_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) {
build_cachefile(cachefile);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 1a0c621ab43..c9a00b0bf0f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -85,10 +85,12 @@ extern "C" {
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_modifier.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_rigidbody.h"
+#include "BKE_shader_fx.h"
#include "BKE_sound.h"
#include "BKE_tracking.h"
#include "BKE_world.h"
@@ -525,6 +527,18 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
data.builder = this;
modifiers_foreachIDLink(object, modifier_walk, &data);
}
+ /* Grease Pencil Modifiers. */
+ if (object->greasepencil_modifiers.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data);
+ }
+ /* Shader FX. */
+ if (object->shader_fx.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ BKE_shaderfx_foreachIDLink(object, modifier_walk, &data);
+ }
/* Constraints. */
if (object->constraints.first != NULL) {
BuilderWalkUserData data;
@@ -570,10 +584,6 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
if (object->particlesystem.first != NULL) {
build_particles(object);
}
- /* Grease pencil. */
- if (object->gpd != NULL) {
- build_gpencil(object->gpd);
- }
/* Proxy object to copy from. */
if (object->proxy_from != NULL) {
build_object(NULL, object->proxy_from);
@@ -630,6 +640,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object)
case OB_SURF:
case OB_MBALL:
case OB_LATTICE:
+ case OB_GPENCIL:
{
build_object_data_geometry(object);
break;
@@ -1798,6 +1809,42 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
}
}
}
+ /* Grease Pencil Modifiers */
+ if (object->greasepencil_modifiers.first != NULL) {
+ ModifierUpdateDepsgraphContext ctx = {};
+ ctx.scene = scene_;
+ ctx.object = object;
+ LISTBASE_FOREACH(GpencilModifierData *, md, &object->greasepencil_modifiers) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo((GpencilModifierType)md->type);
+ if (mti->updateDepsgraph) {
+ DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
+ ctx.node = reinterpret_cast< ::DepsNodeHandle* >(&handle);
+ mti->updateDepsgraph(md, &ctx);
+ }
+ if (BKE_object_modifier_gpencil_use_time(object, md)) {
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, obdata_ubereval_key, "Time Source");
+ }
+ }
+ }
+ /* Shader FX */
+ if (object->shader_fx.first != NULL) {
+ ModifierUpdateDepsgraphContext ctx = {};
+ ctx.scene = scene_;
+ ctx.object = object;
+ LISTBASE_FOREACH(ShaderFxData *, fx, &object->shader_fx) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo((ShaderFxType)fx->type);
+ if (fxi->updateDepsgraph) {
+ DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
+ ctx.node = reinterpret_cast< ::DepsNodeHandle* >(&handle);
+ fxi->updateDepsgraph(fx, &ctx);
+ }
+ if (BKE_object_shaderfx_use_time(object, fx)) {
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, obdata_ubereval_key, "Time Source");
+ }
+ }
+ }
/* Materials. */
if (object->totcol) {
for (int a = 1; a <= object->totcol; a++) {
@@ -1895,13 +1942,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
}
/* Link object data evaluation node to exit operation. */
OperationKey obdata_geom_eval_key(obdata,
- DEG_NODE_TYPE_GEOMETRY,
- DEG_OPCODE_PLACEHOLDER,
- "Geometry Eval");
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
OperationKey obdata_geom_done_key(obdata,
- DEG_NODE_TYPE_GEOMETRY,
- DEG_OPCODE_PLACEHOLDER,
- "Eval Done");
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_PLACEHOLDER,
+ "Eval Done");
add_relation(obdata_geom_eval_key,
obdata_geom_done_key,
"ObData Geom Eval Done");
@@ -1917,35 +1964,67 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
Curve *cu = (Curve *)obdata;
if (cu->bevobj != NULL) {
ComponentKey bevob_geom_key(&cu->bevobj->id,
- DEG_NODE_TYPE_GEOMETRY);
+ DEG_NODE_TYPE_GEOMETRY);
add_relation(bevob_geom_key,
- obdata_geom_eval_key,
- "Curve Bevel Geometry");
+ obdata_geom_eval_key,
+ "Curve Bevel Geometry");
ComponentKey bevob_key(&cu->bevobj->id,
- DEG_NODE_TYPE_TRANSFORM);
+ DEG_NODE_TYPE_TRANSFORM);
add_relation(bevob_key,
- obdata_geom_eval_key,
- "Curve Bevel Transform");
+ obdata_geom_eval_key,
+ "Curve Bevel Transform");
build_object(NULL, cu->bevobj);
}
if (cu->taperobj != NULL) {
ComponentKey taperob_key(&cu->taperobj->id,
- DEG_NODE_TYPE_GEOMETRY);
+ DEG_NODE_TYPE_GEOMETRY);
add_relation(taperob_key, obdata_geom_eval_key, "Curve Taper");
build_object(NULL, cu->taperobj);
}
if (cu->textoncurve != NULL) {
ComponentKey textoncurve_key(&cu->textoncurve->id,
- DEG_NODE_TYPE_GEOMETRY);
+ DEG_NODE_TYPE_GEOMETRY);
add_relation(textoncurve_key,
- obdata_geom_eval_key,
- "Text on Curve");
+ obdata_geom_eval_key,
+ "Text on Curve");
build_object(NULL, cu->textoncurve);
}
break;
}
case ID_LT:
break;
+ case ID_GD: /* Grease Pencil */
+ {
+ bGPdata *gpd = (bGPdata *)obdata;
+
+ /* Geometry cache needs to be recalculated on frame change
+ * (e.g. to fix crashes after scrubbing the timeline when
+ * onion skinning is enabled, since the ghosts need to be
+ * re-added to the cache once scrubbing ends)
+ */
+ TimeSourceKey time_key;
+ ComponentKey geometry_key(obdata, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(time_key,
+ geometry_key,
+ "GP Frame Change");
+
+ /* Geometry cache also needs to be recalculated when Material
+ * settings change (e.g. when fill.opacity changes on/off,
+ * we need to rebuild the bGPDstroke->triangles caches)
+ */
+ for (int i = 0; i < gpd->totcol; i++) {
+ Material *ma = gpd->mat[i];
+ if ((ma != NULL) && (ma->gp_style != NULL)) {
+ OperationKey material_key(&ma->id,
+ DEG_NODE_TYPE_SHADING,
+ DEG_OPCODE_MATERIAL_UPDATE);
+ add_relation(material_key,
+ geometry_key,
+ "Material -> GP Data");
+ }
+ }
+ break;
+ }
default:
BLI_assert(!"Should not happen");
break;
@@ -2228,6 +2307,11 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDDepsNode *id_node
if (id_type == ID_ME && comp_node->type == DEG_NODE_TYPE_GEOMETRY) {
rel_flag &= ~DEPSREL_FLAG_NO_FLUSH;
}
+ /* materials need update grease pencil objects */
+ if (id_type == ID_MA) {
+ rel_flag &= ~DEPSREL_FLAG_NO_FLUSH;
+ }
+
/* Notes on exceptions:
* - Parameters component is where drivers are living. Changing any
* of the (custom) properties in the original datablock (even the
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
index f069c63f138..78d1a930eb7 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
@@ -123,10 +123,6 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_la
if (scene->nodetree != NULL) {
build_compositor(scene);
}
- /* Grease pencil. */
- if (scene->gpd != NULL) {
- build_gpencil(scene->gpd);
- }
/* Masks. */
LISTBASE_FOREACH (Mask *, mask, &bmain_->mask) {
build_mask(mask);
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 4229f8bf9a2..e4659a7a94d 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -100,6 +100,7 @@ void depsgraph_geometry_tag_to_component(const ID *id,
case OB_FONT:
case OB_LATTICE:
case OB_MBALL:
+ case OB_GPENCIL:
*component_type = DEG_NODE_TYPE_GEOMETRY;
break;
case OB_ARMATURE:
@@ -112,11 +113,17 @@ void depsgraph_geometry_tag_to_component(const ID *id,
case ID_ME:
*component_type = DEG_NODE_TYPE_GEOMETRY;
break;
- case ID_PA:
+ case ID_PA: /* Particles */
return;
case ID_LP:
*component_type = DEG_NODE_TYPE_PARAMETERS;
break;
+ case ID_GD:
+ *component_type = DEG_NODE_TYPE_GEOMETRY;
+ break;
+ case ID_PAL: /* Palettes */
+ *component_type = DEG_NODE_TYPE_PARAMETERS;
+ break;
default:
break;
}
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 6ec7b03501b..d672645dea0 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -123,6 +123,13 @@ set(SRC
engines/workbench/solid_mode.c
engines/workbench/transparent_mode.c
engines/external/external_engine.c
+ engines/gpencil/gpencil_engine.h
+ engines/gpencil/gpencil_engine.c
+ engines/gpencil/gpencil_render.c
+ engines/gpencil/gpencil_cache_utils.c
+ engines/gpencil/gpencil_draw_utils.c
+ engines/gpencil/gpencil_draw_cache_impl.c
+ engines/gpencil/gpencil_shader_fx.c
DRW_engine.h
intern/DRW_render.h
@@ -303,6 +310,33 @@ data_to_c_simple(modes/shaders/particle_strand_frag.glsl SRC)
data_to_c_simple(modes/shaders/particle_strand_vert.glsl SRC)
data_to_c_simple(modes/shaders/volume_velocity_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_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_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_swirl_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl SRC)
+
+
list(APPEND INC
)
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 4d4b486d247..6d8e8a69e29 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -126,6 +126,9 @@ void DRW_draw_depth_loop(
struct Depsgraph *depsgraph,
struct ARegion *ar, struct View3D *v3d);
+/* grease pencil render */
+void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph);
+
/* This is here because GPUViewport needs it */
void DRW_pass_free(struct DRWPass *pass);
struct DRWInstanceDataList *DRW_instance_data_list_create(void);
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
new file mode 100644
index 00000000000..4e01c42d33d
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ */
+
+/** \file blender/draw/engines/gpencil/gpencil_cache_utils.c
+ * \ingroup draw
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_global.h"
+
+#include "ED_gpencil.h"
+#include "ED_view3d.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_view3d_types.h"
+
+#include "gpencil_engine.h"
+
+#include "draw_cache_impl.h"
+
+ /* add a gpencil object to cache to defer drawing */
+tGPencilObjectCache *gpencil_object_cache_add(tGPencilObjectCache *cache_array, Object *ob, bool is_temp,
+ int *gp_cache_size, int *gp_cache_used)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ tGPencilObjectCache *cache_elem = NULL;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ 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;
+ }
+
+ /* zero out all pointers */
+ cache_elem = &cache_array[*gp_cache_used];
+ memset(cache_elem, 0, sizeof(*cache_elem));
+
+ /* save object */
+ cache_elem->ob = ob;
+ cache_elem->temp_ob = is_temp;
+ cache_elem->idx = *gp_cache_used;
+
+ cache_elem->init_grp = 0;
+ cache_elem->end_grp = -1;
+
+ /* calculate zdepth from point of view */
+ float zdepth = 0.0;
+ if (rv3d) {
+ if (rv3d->is_persp) {
+ zdepth = ED_view3d_calc_zfac(rv3d, ob->loc, NULL);
+ }
+ else {
+ zdepth = -dot_v3v3(rv3d->viewinv[2], ob->loc);
+ }
+ }
+ 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->loc, plane_cam);
+ }
+ }
+ cache_elem->zdepth = zdepth;
+ /* increase slots used in cache */
+ (*gp_cache_used)++;
+
+ return cache_array;
+}
+
+/* get current cache data */
+static GpencilBatchCache *gpencil_batch_get_element(Object *ob)
+{
+ bGPdata *gpd = ob->data;
+ if (gpd->runtime.batch_cache_data == NULL) {
+ gpd->runtime.batch_cache_data = BLI_ghash_str_new("GP batch cache data");
+ return NULL;
+ }
+
+ return (GpencilBatchCache *) BLI_ghash_lookup(gpd->runtime.batch_cache_data, ob->id.name);
+}
+
+/* verify if cache is valid */
+static bool gpencil_batch_cache_valid(Object *ob, bGPdata *gpd, int cfra)
+{
+ GpencilBatchCache *cache = gpencil_batch_get_element(ob);
+
+ if (cache == NULL) {
+ return false;
+ }
+
+ cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
+
+ if (cfra != cache->cache_frame) {
+ return false;
+ }
+
+ if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
+ return false;
+ }
+
+ if (cache->is_editmode) {
+ return false;
+ }
+
+ if (cache->is_dirty) {
+ return false;
+ }
+
+ return true;
+}
+
+/* resize the cache to the number of slots */
+static void gpencil_batch_cache_resize(GpencilBatchCache *cache, int slots)
+{
+ cache->cache_size = slots;
+ cache->batch_stroke = MEM_recallocN(cache->batch_stroke, sizeof(struct Gwn_Batch *) * slots);
+ cache->batch_fill = MEM_recallocN(cache->batch_fill, sizeof(struct Gwn_Batch *) * slots);
+ cache->batch_edit = MEM_recallocN(cache->batch_edit, sizeof(struct Gwn_Batch *) * slots);
+ cache->batch_edlin = MEM_recallocN(cache->batch_edlin, sizeof(struct Gwn_Batch *) * slots);
+}
+
+/* check size and increase if no free slots */
+void gpencil_batch_cache_check_free_slots(Object *ob)
+{
+ GpencilBatchCache *cache = gpencil_batch_get_element(ob);
+
+ /* the memory is reallocated by chunks, not for one slot only to improve speed */
+ if (cache->cache_idx >= cache->cache_size) {
+ cache->cache_size += GPENCIL_MIN_BATCH_SLOTS_CHUNK;
+ gpencil_batch_cache_resize(cache, cache->cache_size);
+ }
+}
+
+/* cache init */
+static void gpencil_batch_cache_init(Object *ob, int cfra)
+{
+ GpencilBatchCache *cache = gpencil_batch_get_element(ob);
+ bGPdata *gpd = ob->data;
+
+ if (G.debug_value >= 664) {
+ printf("gpencil_batch_cache_init: %s\n", ob->id.name);
+ }
+
+ if (!cache) {
+ cache = MEM_callocN(sizeof(*cache), __func__);
+ BLI_ghash_insert(gpd->runtime.batch_cache_data, ob->id.name, cache);
+ }
+ else {
+ memset(cache, 0, sizeof(*cache));
+ }
+
+ cache->cache_size = GPENCIL_MIN_BATCH_SLOTS_CHUNK;
+ cache->batch_stroke = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Stroke");
+ cache->batch_fill = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Fill");
+ cache->batch_edit = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Edit");
+ cache->batch_edlin = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Edlin");
+
+ cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
+ gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
+
+ cache->cache_idx = 0;
+ cache->is_dirty = true;
+ cache->cache_frame = cfra;
+}
+
+/* clear cache */
+static void gpencil_batch_cache_clear(GpencilBatchCache *cache, bGPdata *gpd)
+{
+ if (!cache) {
+ return;
+ }
+
+ if (cache->cache_size == 0) {
+ return;
+ }
+
+ if (G.debug_value >= 664) {
+ printf("gpencil_batch_cache_clear: %s\n", gpd->id.name);
+ }
+
+ if (cache->cache_size > 0) {
+ for (int i = 0; i < cache->cache_size; i++) {
+ GPU_BATCH_DISCARD_SAFE(cache->batch_stroke[i]);
+ GPU_BATCH_DISCARD_SAFE(cache->batch_fill[i]);
+ GPU_BATCH_DISCARD_SAFE(cache->batch_edit[i]);
+ GPU_BATCH_DISCARD_SAFE(cache->batch_edlin[i]);
+ }
+ MEM_SAFE_FREE(cache->batch_stroke);
+ MEM_SAFE_FREE(cache->batch_fill);
+ MEM_SAFE_FREE(cache->batch_edit);
+ MEM_SAFE_FREE(cache->batch_edlin);
+ }
+
+ MEM_SAFE_FREE(cache);
+}
+
+/* get cache */
+GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra)
+{
+ bGPdata *gpd = ob->data;
+
+ if (!gpencil_batch_cache_valid(ob, gpd, cfra)) {
+ if (G.debug_value >= 664) {
+ printf("gpencil_batch_cache: %s\n", gpd->id.name);
+ }
+
+ GpencilBatchCache *cache = gpencil_batch_get_element(ob);
+ if (cache) {
+ gpencil_batch_cache_clear(cache, gpd);
+ BLI_ghash_remove(gpd->runtime.batch_cache_data, ob->id.name, NULL, NULL);
+ }
+ gpencil_batch_cache_init(ob, cfra);
+ }
+
+ return gpencil_batch_get_element(ob);
+}
+
+/* set cache as dirty */
+void DRW_gpencil_batch_cache_dirty(bGPdata *gpd)
+{
+ if (gpd->runtime.batch_cache_data == NULL) {
+ return;
+ }
+
+ GHashIterator *ihash = BLI_ghashIterator_new(gpd->runtime.batch_cache_data);
+ while (!BLI_ghashIterator_done(ihash)) {
+ GpencilBatchCache *cache = (GpencilBatchCache *)BLI_ghashIterator_getValue(ihash);
+ if (cache) {
+ cache->is_dirty = true;
+ }
+ BLI_ghashIterator_step(ihash);
+ }
+ BLI_ghashIterator_free(ihash);
+}
+
+/* free batch cache */
+void DRW_gpencil_batch_cache_free(bGPdata *gpd)
+{
+ if (gpd->runtime.batch_cache_data == NULL) {
+ return;
+ }
+
+ GHashIterator *ihash = BLI_ghashIterator_new(gpd->runtime.batch_cache_data);
+ while (!BLI_ghashIterator_done(ihash)) {
+ GpencilBatchCache *cache = (GpencilBatchCache *)BLI_ghashIterator_getValue(ihash);
+ if (cache) {
+ gpencil_batch_cache_clear(cache, gpd);
+ }
+ BLI_ghashIterator_step(ihash);
+ }
+ BLI_ghashIterator_free(ihash);
+
+ /* free hash */
+ if (gpd->runtime.batch_cache_data) {
+ BLI_ghash_free(gpd->runtime.batch_cache_data, NULL, NULL);
+ gpd->runtime.batch_cache_data = 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
new file mode 100644
index 00000000000..dd5db85f3f4
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
@@ -0,0 +1,739 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file draw/engines/gpencil/gpencil_draw_cache_impl.c
+ * \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_gpencil.h"
+#include "BKE_action.h"
+
+#include "DRW_render.h"
+
+#include "GPU_immediate.h"
+#include "GPU_draw.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, float matrix[4][4], const bGPDspoint *pt, int idx,
+ uint pos_id, uint color_id,
+ uint thickness_id, uint uvdata_id, short thickness,
+ const float ink[4])
+{
+ float viewfpt[3];
+
+ 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 */
+ mul_v3_m4v3(viewfpt, matrix, &pt->x);
+ 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 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], 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);
+}
+
+/* create batch geometry data for points stroke shader */
+GPUBatch *DRW_gpencil_get_point_geom(bGPDstroke *gps, short thickness, const float ink[4])
+{
+ static GPUVertFormat format = { 0 };
+ static uint pos_id, color_id, size_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);
+ size_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, gps->totpoints);
+
+ /* draw stroke curve */
+ const bGPDspoint *pt = gps->points;
+ int idx = 0;
+ 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(vbo, color_id, idx, col);
+ GPU_vertbuf_attr_set(vbo, size_id, idx, &thick);
+
+ /* 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);
+
+ GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
+ idx++;
+ }
+
+ return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+/* create batch geometry data for stroke shader */
+GPUBatch *DRW_gpencil_get_stroke_geom(bGPDframe *gpf, 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;
+
+ 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, totpoints + cyclic_add + 2);
+
+ /* draw stroke curve */
+ const bGPDspoint *pt = points;
+ int idx = 0;
+ 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(vbo, gpf->runtime.viewmatrix, &points[totpoints - 1], idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, ink);
+ idx++;
+ }
+ else {
+ gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[1], idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, ink);
+ idx++;
+ }
+ }
+ /* set point */
+ gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, pt, idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, ink);
+ idx++;
+ }
+
+ if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) {
+ /* draw line to first point to complete the cycle */
+ gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[0], idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, ink);
+ idx++;
+ /* now add adjacency point (not drawn) */
+ gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[1], idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, ink);
+ idx++;
+ }
+ /* last adjacency point (not drawn) */
+ else {
+ gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[totpoints - 2], idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, ink);
+ }
+
+ return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+/* create batch geometry data for current buffer stroke shader */
+GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, float matrix[4][4], short thickness)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ View3D *v3d = draw_ctx->v3d;
+ ARegion *ar = draw_ctx->ar;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ ToolSettings *ts = scene->toolsettings;
+ Object *ob = draw_ctx->obact;
+
+ tGPspoint *points = gpd->runtime.sbuffer;
+ int totpoints = gpd->runtime.sbuffer_size;
+
+ 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, totpoints + 2);
+
+ /* draw stroke curve */
+ const tGPspoint *tpt = points;
+ bGPDspoint pt, pt2;
+ int idx = 0;
+
+ /* get origin to reproject point */
+ float origin[3];
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ ED_gp_get_drawing_reference(v3d, scene, ob, gpl, ts->gpencil_v3d_align, origin);
+
+ for (int i = 0; i < totpoints; i++, tpt++) {
+ ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
+ ED_gp_project_point_to_plane(ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
+
+ /* first point for adjacency (not drawn) */
+ if (i == 0) {
+ if (totpoints > 1) {
+ ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt2);
+ gpencil_set_stroke_point(vbo, matrix, &pt2, idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
+ }
+ else {
+ gpencil_set_stroke_point(vbo, matrix, &pt, idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
+ }
+ idx++;
+ }
+ /* set point */
+ gpencil_set_stroke_point(vbo, matrix, &pt, idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
+ idx++;
+ }
+
+ /* last adjacency point (not drawn) */
+ if (totpoints > 2) {
+ ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 2], &pt2);
+ gpencil_set_stroke_point(vbo, matrix, &pt2, idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
+ }
+ else {
+ gpencil_set_stroke_point(vbo, matrix, &pt, idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
+ }
+
+ 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 *DRW_gpencil_get_buffer_point_geom(bGPdata *gpd, float matrix[4][4], short thickness)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ View3D *v3d = draw_ctx->v3d;
+ ARegion *ar = draw_ctx->ar;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ ToolSettings *ts = scene->toolsettings;
+ Object *ob = draw_ctx->obact;
+
+ tGPspoint *points = gpd->runtime.sbuffer;
+ int totpoints = gpd->runtime.sbuffer_size;
+
+ 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, 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(v3d, scene, ob, gpl, ts->gpencil_v3d_align, origin);
+
+ for (int i = 0; i < totpoints; i++, tpt++) {
+ ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
+ ED_gp_project_point_to_plane(ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
+
+ /* set point */
+ gpencil_set_stroke_point(vbo, matrix, &pt, idx,
+ pos_id, color_id, thickness_id, uvdata_id,
+ 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 fill shader */
+GPUBatch *DRW_gpencil_get_buffer_fill_geom(bGPdata *gpd)
+{
+ if (gpd == NULL) {
+ return NULL;
+ }
+
+ const tGPspoint *points = gpd->runtime.sbuffer;
+ int totpoints = gpd->runtime.sbuffer_size;
+ if (totpoints < 3) {
+ return NULL;
+ }
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ View3D *v3d = draw_ctx->v3d;
+ ARegion *ar = draw_ctx->ar;
+ 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(v3d, 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(ar, 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);
+}
+
+/* create batch geometry data for stroke shader */
+GPUBatch *DRW_gpencil_get_fill_geom(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_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
+ DRW_gpencil_triangulate_stroke_fill(gps);
+ ED_gpencil_calc_stroke_uv(ob, gps);
+ }
+
+ BLI_assert(gps->tot_triangles >= 1);
+
+ static GPUVertFormat format = { 0 };
+ static uint pos_id, color_id, text_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);
+ text_id = GPU_vertformat_attr_add(&format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, gps->tot_triangles * 3);
+
+ /* Draw all triangles for filling the polygon (cache must be calculated before) */
+ bGPDtriangle *stroke_triangle = gps->triangles;
+ int idx = 0;
+ for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
+ for (int j = 0; j < 3; j++) {
+ gpencil_set_fill_point(
+ vbo, idx, &gps->points[stroke_triangle->verts[j]], color, stroke_triangle->uv[j],
+ pos_id, color_id, text_id);
+ idx++;
+ }
+ }
+
+ return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+/* Draw selected verts for strokes being edited */
+GPUBatch *DRW_gpencil_get_edit_geom(bGPDstroke *gps, float alpha, short dflag)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Object *ob = draw_ctx->obact;
+ bGPdata *gpd = ob->data;
+ bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
+
+ 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;
+
+ 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);
+ color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ size_id = GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 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;
+
+ int idx = 0;
+ float fcolor[4];
+ float fsize = 0;
+ for (int i = 0; i < gps->totpoints; i++, pt++, dvert++) {
+ /* weight paint */
+ if (is_weight_paint) {
+ float weight = BKE_gpencil_vgroup_use_index(dvert, vgindex);
+ CLAMP(weight, 0.0f, 1.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 (pt->flag & GP_SPOINT_SELECT) {
+ copy_v4_v4(fcolor, selectColor);
+ fsize = vsize;
+ }
+ else {
+ copy_v4_v4(fcolor, gps->runtime.tmp_stroke_rgba);
+ fsize = bsize;
+ }
+ }
+
+ GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor);
+ GPU_vertbuf_attr_set(vbo, size_id, idx, &fsize);
+ GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
+ idx++;
+ }
+
+ return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+/* Draw lines for strokes being edited */
+GPUBatch *DRW_gpencil_get_edlin_geom(bGPDstroke *gps, float alpha, short UNUSED(dflag))
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Object *ob = draw_ctx->obact;
+ bGPdata *gpd = ob->data;
+ 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);
+
+ 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, gps->totpoints);
+
+ /* Draw all the stroke lines (selected or not) */
+ bGPDspoint *pt = gps->points;
+
+ /* GPXX: for some converted files, this struct could be null
+ * maybe we can remove this and move to versioning code after
+ * merge */
+ if (gps->dvert == NULL) {
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights");
+ }
+
+ MDeformVert *dvert = gps->dvert;
+
+ int idx = 0;
+ float fcolor[4];
+ for (int i = 0; i < gps->totpoints; i++, pt++, dvert++) {
+ /* weight paint */
+ if (is_weight_paint) {
+ float weight = BKE_gpencil_vgroup_use_index(dvert, vgindex);
+ CLAMP(weight, 0.0f, 1.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) {
+ copy_v4_v4(fcolor, selectColor);
+ }
+ else {
+ copy_v4_v4(fcolor, linecolor);
+ }
+ }
+
+ GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor);
+ GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
+ idx++;
+ }
+
+ return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+static void set_grid_point(GPUVertBuf *vbo, int idx, float col_grid[4],
+ uint pos_id, uint color_id,
+ float v1, float v2, int axis)
+{
+ GPU_vertbuf_attr_set(vbo, color_id, idx, col_grid);
+
+ float pos[3];
+ /* Set the grid in the selected axis (default is always Y axis) */
+ if (axis & V3D_GP_GRID_AXIS_X) {
+ pos[0] = 0.0f;
+ pos[1] = v1;
+ pos[2] = v2;
+ }
+ else if (axis & V3D_GP_GRID_AXIS_Z) {
+ pos[0] = v1;
+ pos[1] = v2;
+ pos[2] = 0.0f;
+ }
+ else
+ {
+ pos[0] = v1;
+ pos[1] = 0.0f;
+ pos[2] = v2;
+ }
+
+
+
+ GPU_vertbuf_attr_set(vbo, pos_id, idx, pos);
+}
+
+/* Draw grid lines */
+GPUBatch *DRW_gpencil_get_grid(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ ToolSettings *ts = scene->toolsettings;
+ View3D *v3d = draw_ctx->v3d;
+
+ float col_grid[4];
+
+ /* verify we have something to draw and valid values */
+ if (v3d->overlay.gpencil_grid_lines < 1) {
+ v3d->overlay.gpencil_grid_lines = GP_DEFAULT_GRID_LINES;
+ }
+
+ if (v3d->overlay.gpencil_grid_scale == 0.0f) {
+ v3d->overlay.gpencil_grid_scale = 1.0f;
+ }
+
+ if (v3d->overlay.gpencil_grid_opacity < 0.1f) {
+ v3d->overlay.gpencil_grid_opacity = 0.1f;
+ }
+
+ UI_GetThemeColor3fv(TH_GRID, col_grid);
+ col_grid[3] = v3d->overlay.gpencil_grid_opacity;
+
+ /* if use locked axis, copy value */
+ int axis = v3d->overlay.gpencil_grid_axis;
+ if ((v3d->overlay.gpencil_grid_axis & V3D_GP_GRID_AXIS_LOCK) == 0) {
+
+ axis = v3d->overlay.gpencil_grid_axis;
+ }
+ else {
+ switch (ts->gp_sculpt.lock_axis) {
+ case GP_LOCKAXIS_X:
+ {
+ axis = V3D_GP_GRID_AXIS_X;
+ break;
+ }
+ case GP_LOCKAXIS_NONE:
+ case GP_LOCKAXIS_Y:
+ {
+ axis = V3D_GP_GRID_AXIS_Y;
+ break;
+ }
+ case GP_LOCKAXIS_Z:
+ {
+ axis = V3D_GP_GRID_AXIS_Z;
+ break;
+ }
+ }
+ }
+
+ const char *grid_unit = NULL;
+ const int gridlines = v3d->overlay.gpencil_grid_lines;
+ const float grid_scale = v3d->overlay.gpencil_grid_scale * ED_scene_grid_scale(scene, &grid_unit);
+ const float grid = grid_scale;
+ const float space = (grid_scale / gridlines);
+
+ 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 = a * space;
+
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid, -line, axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid, -line, axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid, +line, axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid, +line, axis);
+ idx++;
+
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, -line, -grid, axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, -line, +grid, axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, +line, -grid, axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, +line, +grid, axis);
+ idx++;
+ }
+ /* center lines */
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid, 0.0f, axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid, 0.0f, axis);
+ idx++;
+
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, 0.0f, -grid, axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, 0.0f, +grid, 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_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
new file mode 100644
index 00000000000..76cb1405a71
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -0,0 +1,1336 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ */
+
+/** \file blender/draw/engines/gpencil/gpencil_draw_utils.c
+ * \ingroup draw
+ */
+
+#include "BLI_polyfill_2d.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BKE_brush.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_image.h"
+#include "BKE_material.h"
+
+#include "ED_gpencil.h"
+#include "ED_view3d.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_material_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_gpencil_modifier_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"
+
+/* fill type to communicate to shader */
+#define SOLID 0
+#define GRADIENT 1
+#define RADIAL 2
+#define CHESS 3
+#define TEXTURE 4
+#define PATTERN 5
+
+/* 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;
+}
+
+/* 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], bool expand)
+{
+ 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];
+ }
+ }
+ /* 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 gpencil_calc_stroke_fill_uv(
+ const float(*points2d)[2], int totpoints, 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];
+ }
+}
+
+/* Get points of stroke always flat to view not affected by camera view or view position */
+static void gpencil_stroke_2d_flat(const bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction)
+{
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+
+ float locx[3];
+ float locy[3];
+ float loc3[3];
+ float normal[3];
+
+ /* local X axis (p0 -> p1) */
+ sub_v3_v3v3(locx, &pt1->x, &pt0->x);
+
+ /* point vector at 3/4 */
+ sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
+
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(normal, locx, loc3);
+
+ /* local Y axis (cross to normal/x axis) */
+ cross_v3_v3v3(locy, normal, locx);
+
+ /* Normalize vectors */
+ normalize_v3(locx);
+ normalize_v3(locy);
+
+ /* Get all points in local space */
+ for (int i = 0; i < totpoints; i++) {
+ const bGPDspoint *pt = &points[i];
+ float loc[3];
+
+ /* Get local space using first point as origin */
+ sub_v3_v3v3(loc, &pt->x, &pt0->x);
+
+ points2d[i][0] = dot_v3v3(loc, locx);
+ points2d[i][1] = dot_v3v3(loc, locy);
+ }
+
+ /* Concave (-1), Convex (1), or Autodetect (0)? */
+ *r_direction = (int)locy[2];
+}
+
+/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */
+void DRW_gpencil_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 */
+ 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 */
+ gpencil_calc_2d_bounding_box(points2d, gps->totpoints, minv, maxv, false);
+ /* calc uv data */
+ gpencil_calc_stroke_fill_uv(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(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]]);
+ }
+ }
+ 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_CACHES) {
+ gps->flag &= ~GP_STROKE_RECALC_CACHES;
+ }
+
+ /* clear memory */
+ MEM_SAFE_FREE(tmp_triangles);
+ MEM_SAFE_FREE(points2d);
+ MEM_SAFE_FREE(uv);
+}
+
+/* recalc the internal geometry caches for fill and uvs */
+static void DRW_gpencil_recalc_geometry_caches(Object *ob, MaterialGPencilStyle *gp_style, bGPDstroke *gps)
+{
+ if (gps->flag & GP_STROKE_RECALC_CACHES) {
+ /* 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->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)))
+ {
+ DRW_gpencil_triangulate_stroke_fill(gps);
+ }
+ }
+
+ /* calc uv data along the stroke */
+ ED_gpencil_calc_stroke_uv(ob, gps);
+
+ /* clear flag */
+ gps->flag &= ~GP_STROKE_RECALC_CACHES;
+ }
+}
+
+/* create shading group for filling */
+static DRWShadingGroup *DRW_gpencil_shgroup_fill_create(
+ GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass,
+ GPUShader *shader, bGPdata *gpd, MaterialGPencilStyle *gp_style, int id)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+
+ /* e_data.gpencil_fill_sh */
+ DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
+
+ 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_CHESSBOARD:
+ stl->shgroups[id].fill_style = CHESS;
+ 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);
+
+ stl->shgroups[id].texture_mix = gp_style->flag & GP_STYLE_COLOR_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);
+
+ DRW_shgroup_uniform_int(grp, "xraymode", (const int *) &gpd->xray_mode, 1);
+ /* image texture */
+ if ((gp_style->flag & GP_STYLE_COLOR_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, GL_TEXTURE_2D, true, 0.0);
+ DRW_shgroup_uniform_texture(grp, "myTexture", texture);
+
+ 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;
+}
+
+/* create shading group for strokes */
+DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(
+ GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob,
+ bGPdata *gpd, MaterialGPencilStyle *gp_style, int id, bool onion)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ const float *viewport_size = DRW_viewport_size_get();
+
+ /* 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_float(grp, "pixelsize", &U.pixelsize, 1);
+
+ /* avoid wrong values */
+ if ((gpd) && (gpd->pixfactor == 0)) {
+ gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
+ }
+
+ /* object scale and depth */
+ if ((ob) && (id > -1)) {
+ stl->shgroups[id].obj_scale = (ob->size[0] + ob->size[1] + ob->size[2]) / 3.0f;
+ 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);
+ }
+ 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);
+ }
+ }
+
+ if ((gpd) && (id > -1)) {
+ DRW_shgroup_uniform_int(grp, "xraymode", (const int *) &gpd->xray_mode, 1);
+ }
+ else {
+ /* for drawing always on front */
+ DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
+ }
+
+ /* 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, GL_TEXTURE_2D, true, 0.0f);
+ DRW_shgroup_uniform_texture(grp, "myTexture", texture);
+
+ 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 volumetrics */
+static DRWShadingGroup *DRW_gpencil_shgroup_point_create(
+ GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob,
+ bGPdata *gpd, MaterialGPencilStyle *gp_style, int id, bool onion)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ const float *viewport_size = DRW_viewport_size_get();
+
+ /* 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_float(grp, "pixelsize", &U.pixelsize, 1);
+
+ /* avoid wrong values */
+ if ((gpd) && (gpd->pixfactor == 0)) {
+ gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
+ }
+
+ /* object scale and depth */
+ if ((ob) && (id > -1)) {
+ stl->shgroups[id].obj_scale = (ob->size[0] + ob->size[1] + ob->size[2]) / 3.0f;
+ 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);
+ }
+ 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);
+ }
+ }
+
+ if (gpd) {
+ DRW_shgroup_uniform_int(grp, "xraymode", (const int *)&gpd->xray_mode, 1);
+ }
+ else {
+ /* for drawing always on front */
+ DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
+ }
+
+ /* 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, GL_TEXTURE_2D, true, 0.0f);
+ DRW_shgroup_uniform_texture(grp, "myTexture", texture);
+
+ 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 shading group to pass */
+static void gpencil_add_fill_shgroup(
+ GpencilBatchCache *cache, DRWShadingGroup *fillgrp,
+ Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps,
+ const float tintcolor[4], const bool onion, const bool custonion)
+{
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(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] * gpl->opacity;
+ if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
+ 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;
+ }
+ }
+ if (cache->is_dirty) {
+ gpencil_batch_cache_check_free_slots(ob);
+ cache->batch_fill[cache->cache_idx] = DRW_gpencil_get_fill_geom(ob, gps, color);
+ }
+ DRW_shgroup_call_add(fillgrp, cache->batch_fill[cache->cache_idx], gpf->runtime.viewmatrix);
+ }
+ }
+}
+
+/* add stroke shading group to pass */
+static void gpencil_add_stroke_shgroup(GpencilBatchCache *cache, DRWShadingGroup *strokegrp,
+ 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_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+
+ /* set color using base color, tint color and opacity */
+ 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 (cache->is_dirty) {
+ gpencil_batch_cache_check_free_slots(ob);
+ if ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
+ cache->batch_stroke[cache->cache_idx] = DRW_gpencil_get_stroke_geom(gpf, gps, sthickness, ink);
+ }
+ else {
+ cache->batch_stroke[cache->cache_idx] = DRW_gpencil_get_point_geom(gps, sthickness, ink);
+ }
+ }
+ DRW_shgroup_call_add(strokegrp, cache->batch_stroke[cache->cache_idx], gpf->runtime.viewmatrix);
+}
+
+/* add edit points shading group to pass */
+static void gpencil_add_editpoints_shgroup(
+ GPENCIL_StorageList *stl, GpencilBatchCache *cache, ToolSettings *UNUSED(ts), Object *ob,
+ bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(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);
+
+ /* line of the original stroke */
+ if (cache->is_dirty) {
+ gpencil_batch_cache_check_free_slots(ob);
+ cache->batch_edlin[cache->cache_idx] = DRW_gpencil_get_edlin_geom(gps, edit_alpha, gpd->flag);
+ }
+ if (cache->batch_edlin[cache->cache_idx]) {
+ if ((obact) && (obact == ob) &&
+ ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (v3d->flag3 & V3D_GP_SHOW_EDIT_LINES))
+ {
+ DRW_shgroup_call_add(
+ stl->g_data->shgrps_edit_line,
+ cache->batch_edlin[cache->cache_idx],
+ gpf->runtime.viewmatrix);
+ }
+ }
+ /* 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 (cache->is_dirty) {
+ gpencil_batch_cache_check_free_slots(ob);
+ cache->batch_edit[cache->cache_idx] = DRW_gpencil_get_edit_geom(gps, edit_alpha, gpd->flag);
+ }
+ if (cache->batch_edit[cache->cache_idx]) {
+ if ((obact) && (obact == ob)) {
+ /* edit pass */
+ DRW_shgroup_call_add(
+ stl->g_data->shgrps_edit_point,
+ cache->batch_edit[cache->cache_idx],
+ gpf->runtime.viewmatrix);
+ }
+ }
+ }
+ }
+ }
+}
+
+/* function to draw strokes for onion only */
+static void gpencil_draw_onion_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)
+{
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ Depsgraph *depsgraph = DRW_context_state_get()->depsgraph;
+
+ float viewmatrix[4][4];
+
+ /* get parent matrix and save as static data */
+ ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, viewmatrix);
+ copy_m4_m4(gpf->runtime.viewmatrix, viewmatrix);
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ 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;
+ }
+
+ stl->shgroups[id].shgrps_fill = NULL;
+ if ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
+ stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_stroke_create(
+ e_data, vedata, psl->stroke_pass, e_data->gpencil_stroke_sh, ob, gpd, gp_style, id, true);
+ }
+ else {
+ stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_point_create(
+ e_data, vedata, psl->stroke_pass, e_data->gpencil_point_sh, ob, gpd, gp_style, id, true);
+ }
+
+ /* stroke */
+ gpencil_add_stroke_shgroup(
+ cache, stl->shgroups[id].shgrps_stroke, ob, gpl, gpf, gps, opacity, tintcolor, true, custonion);
+
+ stl->storage->shgroup_id++;
+ cache->cache_idx++;
+ }
+}
+
+
+/* main function to draw strokes */
+static void gpencil_draw_strokes(
+ GpencilBatchCache *cache, GPENCIL_e_data *e_data, void *vedata, ToolSettings *ts, Object *ob,
+ bGPdata *gpd, bGPDlayer *gpl, bGPDframe *src_gpf, bGPDframe *derived_gpf,
+ const float opacity, const float tintcolor[4], const bool custonion)
+{
+ 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, *src_gps;
+ DRWShadingGroup *fillgrp;
+ DRWShadingGroup *strokegrp;
+ float viewmatrix[4][4];
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const bool playing = (bool)stl->storage->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->flag3 & 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 */
+ ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, viewmatrix);
+ copy_m4_m4(derived_gpf->runtime.viewmatrix, viewmatrix);
+
+ /* apply geometry modifiers */
+ if ((cache->is_dirty) && (ob->greasepencil_modifiers.first) && (!is_multiedit)) {
+ if (!stl->storage->simplify_modif) {
+ if (BKE_gpencil_has_geometry_modifiers(ob)) {
+ BKE_gpencil_geometry_modifiers(depsgraph, ob, gpl, derived_gpf, stl->storage->is_render);
+ }
+ }
+ }
+
+ if (src_gpf) {
+ src_gps = src_gpf->strokes.first;
+ }
+ else {
+ src_gps = NULL;
+ }
+
+ for (gps = derived_gpf->strokes.first; gps; gps = gps->next) {
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(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;
+ }
+ /* limit the number of shading groups */
+ if (stl->storage->shgroup_id >= GPENCIL_MAX_SHGROUPS) {
+ continue;
+ }
+
+ /* be sure recalc all chache in source stroke to avoid recalculation when frame change
+ * and improve fps */
+ if (src_gps) {
+ DRW_gpencil_recalc_geometry_caches(ob, gp_style, src_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))
+ {
+ continue;
+ }
+ }
+
+ if ((gpl->actframe->framenum == derived_gpf->framenum) ||
+ (!is_multiedit) || (overlay_multiedit))
+ {
+ int id = stl->storage->shgroup_id;
+ if (gps->totpoints > 0) {
+ if ((gps->totpoints > 2) && (!stl->storage->simplify_fill) &&
+ ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) &&
+ ((gps->flag & GP_STROKE_NOFILL) == 0))
+ {
+ stl->shgroups[id].shgrps_fill = DRW_gpencil_shgroup_fill_create(
+ e_data, vedata, psl->stroke_pass, e_data->gpencil_fill_sh, gpd, gp_style, id);
+ }
+ else {
+ stl->shgroups[id].shgrps_fill = NULL;
+ }
+ if ((gp_style->mode == GP_STYLE_MODE_LINE) && (gps->totpoints > 1)) {
+ stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_stroke_create(
+ e_data, vedata, psl->stroke_pass, e_data->gpencil_stroke_sh, ob, gpd, gp_style, id, false);
+ }
+ else {
+ stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_point_create(
+ e_data, vedata, psl->stroke_pass, e_data->gpencil_point_sh, ob, gpd, gp_style, id, false);
+ }
+ }
+ else {
+ stl->shgroups[id].shgrps_fill = NULL;
+ stl->shgroups[id].shgrps_stroke = NULL;
+ }
+ stl->storage->shgroup_id++;
+
+ fillgrp = stl->shgroups[id].shgrps_fill;
+ strokegrp = stl->shgroups[id].shgrps_stroke;
+
+ /* copy color to temp fields to apply temporal changes in the stroke */
+ copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+
+ /* apply modifiers (only modify geometry, but not create ) */
+ if ((cache->is_dirty) && (ob->greasepencil_modifiers.first) && (!is_multiedit)) {
+ if (!stl->storage->simplify_modif) {
+ BKE_gpencil_stroke_modifiers(depsgraph, ob, gpl, derived_gpf, gps, stl->storage->is_render);
+ }
+ }
+
+ /* fill */
+ if ((fillgrp) && (!stl->storage->simplify_fill)) {
+ gpencil_add_fill_shgroup(
+ cache, fillgrp, ob, gpl, derived_gpf, gps, tintcolor, false, custonion);
+ }
+ /* stroke */
+ if (strokegrp) {
+ gpencil_add_stroke_shgroup(
+ cache, strokegrp, ob, gpl, derived_gpf, gps, opacity, tintcolor, false, custonion);
+ }
+ }
+
+ /* edit points (only in edit mode and not play animation not render) */
+ if ((src_gps) && (!playing) && (!is_render)) {
+ if (!stl->g_data->shgrps_edit_line) {
+ stl->g_data->shgrps_edit_line = DRW_shgroup_create(e_data->gpencil_line_sh, psl->edit_pass);
+ }
+ 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);
+ }
+
+ gpencil_add_editpoints_shgroup(stl, cache, ts, ob, gpd, gpl, derived_gpf, src_gps);
+ }
+
+ if (src_gps) {
+ src_gps = src_gps->next;
+ }
+
+ cache->cache_idx++;
+ }
+}
+
+ /* draw stroke in drawing buffer */
+void DRW_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;
+ Brush *brush = BKE_brush_getactive_gpencil(ts);
+ bGPdata *gpd = ob->data;
+ MaterialGPencilStyle *gp_style = NULL;
+
+ float obscale = (ob->size[0] + ob->size[1] + ob->size[2]) / 3.0f;
+
+ /* use the brush material */
+ Material *ma = BKE_gpencil_get_material_from_brush(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_material_gpencil_settings_get(ob, ob->actcol);
+ }
+
+ /* 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 (ED_gpencil_session_active() && (gpd->runtime.sbuffer_size > 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;
+ /* if only one point, don't need to draw buffer because the user has no time to see it */
+ if (gpd->runtime.sbuffer_size > 1) {
+ if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
+ stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_stroke_create(
+ e_data, vedata, psl->drawing_pass, e_data->gpencil_stroke_sh, NULL, gpd, gp_style, -1, false);
+ }
+ else {
+ stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_point_create(
+ e_data, vedata, psl->drawing_pass, e_data->gpencil_point_sh, NULL, gpd, gp_style, -1, false);
+ }
+
+ /* 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 = DRW_gpencil_get_buffer_stroke_geom(
+ gpd, stl->storage->unit_matrix, lthick);
+ }
+ else {
+ stl->g_data->batch_buffer_stroke = DRW_gpencil_get_buffer_point_geom(
+ gpd, stl->storage->unit_matrix, lthick);
+ }
+
+ DRW_shgroup_call_add(
+ stl->g_data->shgrps_drawing_stroke,
+ stl->g_data->batch_buffer_stroke,
+ stl->storage->unit_matrix);
+
+ if ((gpd->runtime.sbuffer_size >= 3) && (gpd->runtime.sfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) &&
+ ((gpd->runtime.sbuffer_sflag & GP_STROKE_NOFILL) == 0))
+ {
+ /* 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);
+ stl->g_data->batch_buffer_fill = DRW_gpencil_get_buffer_fill_geom(gpd);
+ DRW_shgroup_call_add(
+ stl->g_data->shgrps_drawing_fill,
+ stl->g_data->batch_buffer_fill,
+ stl->storage->unit_matrix);
+ }
+ }
+ }
+ }
+}
+
+/* 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);
+}
+
+/* draw onion-skinning for a layer */
+static void gpencil_draw_onionskins(
+ GpencilBatchCache *cache, GPENCIL_e_data *e_data, 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;
+ int mode = 0;
+ bool colflag = false;
+ bGPDframe *gpf_loop = NULL;
+ int last = gpf->framenum;
+
+ colflag = (bool)gpd->onion_flag & GP_ONION_GHOST_PREVCOL;
+
+
+ /* -------------------------------
+ * 1) Draw Previous Frames First
+ * ------------------------------- */
+ step = gpd->gstep;
+ mode = gpd->onion_mode;
+
+ 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;
+ }
+ /* 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_ABSOLUTE) && (gpd->onion_flag & GP_ONION_LOOP)) {
+ gpf_loop = gf;
+ }
+
+ gpencil_get_onion_alpha(color, gpd);
+ gpencil_draw_onion_strokes(cache, e_data, vedata, ob, gpd, gpl, gf, color[3], color, colflag);
+ }
+ /* -------------------------------
+ * 2) Now draw next frames
+ * ------------------------------- */
+ step = gpd->gstep_next;
+ mode = gpd->onion_mode;
+
+ 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;
+ }
+ /* 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, e_data, 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, e_data, vedata, ob, gpd, gpl,
+ gpf_loop, color[3], color, colflag);
+ }
+ }
+}
+
+/* populate a datablock for multiedit (no onions, no modifiers) */
+void DRW_gpencil_populate_multiedit(GPENCIL_e_data *e_data, void *vedata, Scene *scene, Object *ob, bGPdata *gpd)
+{
+ bGPDframe *gpf = NULL;
+
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
+ GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
+ ToolSettings *ts = scene->toolsettings;
+ cache->cache_idx = 0;
+
+ /* check if playing animation */
+ bool playing = (bool)stl->storage->playing;
+
+ /* 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;
+
+ /* 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, ts, ob, gpd, gpl, gpf, gpf,
+ gpl->opacity, gpl->tintcolor, false);
+ }
+ }
+ }
+ else {
+ gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0);
+ if (gpf) {
+ gpencil_draw_strokes(
+ cache, e_data, vedata, ts, ob, gpd, gpl, gpf, gpf,
+ gpl->opacity, gpl->tintcolor, false);
+ }
+ }
+
+ }
+
+ cache->is_dirty = false;
+}
+
+/* helper for populate a complete grease pencil datablock */
+void DRW_gpencil_populate_datablock(GPENCIL_e_data *e_data, void *vedata, Scene *scene, Object *ob, bGPdata *gpd)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
+ ToolSettings *ts = scene->toolsettings;
+ bGPDframe *derived_gpf = NULL;
+ const bool main_onion = v3d != NULL ? ((v3d->flag3 & V3D_GP_SHOW_ONION_SKIN) == 0) : true;
+ const bool no_onion = (bool)(gpd->flag & GP_DATA_STROKE_WEIGHTMODE) || main_onion;
+ const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) : true;
+
+ /* check if playing animation */
+ bool playing = (bool)stl->storage->playing;
+
+ GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
+ cache->cache_idx = 0;
+
+ /* init general modifiers data */
+ if (!stl->storage->simplify_modif) {
+ if ((cache->is_dirty) && (ob->greasepencil_modifiers.first)) {
+ BKE_gpencil_lattice_init(ob);
+ }
+ }
+ /* 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;
+
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0);
+ if (gpf == NULL)
+ continue;
+
+ /* create GHash if need */
+ if (gpl->runtime.derived_data == NULL) {
+ gpl->runtime.derived_data = (GHash *)BLI_ghash_str_new(gpl->info);
+ }
+
+ derived_gpf = BLI_ghash_lookup(gpl->runtime.derived_data, ob->id.name);
+ if (derived_gpf == NULL) {
+ cache->is_dirty = true;
+ }
+ if (cache->is_dirty) {
+ if (derived_gpf != NULL) {
+ /* first clear temp data */
+ BKE_gpencil_free_frame_runtime_data(derived_gpf);
+ BLI_ghash_remove(gpl->runtime.derived_data, ob->id.name, NULL, NULL);
+ }
+ /* create new data */
+ derived_gpf = BKE_gpencil_frame_duplicate(gpf);
+ BLI_ghash_insert(gpl->runtime.derived_data, ob->id.name, derived_gpf);
+ }
+
+ /* draw onion skins */
+ if ((gpd->flag & GP_DATA_SHOW_ONIONSKINS) &&
+ (!no_onion) && (overlay) &&
+ (gpl->onion_flag & GP_LAYER_ONIONSKIN) &&
+ ((!playing) || (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)))
+ {
+ if ((!stl->storage->is_render) ||
+ ((stl->storage->is_render) && (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)))
+ {
+ gpencil_draw_onionskins(cache, e_data, vedata, ob, gpd, gpl, gpf);
+ }
+ }
+
+ /* draw normal strokes */
+ gpencil_draw_strokes(
+ cache, e_data, vedata, ts, ob, gpd, gpl, gpf, derived_gpf,
+ gpl->opacity, gpl->tintcolor, false);
+
+ }
+
+ /* clear any lattice data */
+ if ((cache->is_dirty) && (ob->greasepencil_modifiers.first)) {
+ BKE_gpencil_lattice_clear(ob);
+ }
+
+ cache->is_dirty = false;
+}
+
+/* Helper for gpencil_instance_modifiers()
+ * See also MOD_gpencilinstance.c -> bakeModifier()
+ */
+static void gp_instance_modifier_make_instances(GPENCIL_StorageList *stl, Object *ob, InstanceGpencilModifierData *mmd)
+{
+ /* reset random */
+ mmd->rnd[0] = 1;
+
+ /* Generate instances */
+ for (int x = 0; x < mmd->count[0]; x++) {
+ for (int y = 0; y < mmd->count[1]; y++) {
+ for (int z = 0; z < mmd->count[2]; z++) {
+ Object *newob;
+
+ const int elem_idx[3] = {x, y, z};
+ float mat[4][4];
+ int sh;
+
+ /* original strokes are at index = 0,0,0 */
+ if ((x == 0) && (y == 0) && (z == 0)) {
+ continue;
+ }
+
+ /* compute transform for instance */
+ BKE_gpencil_instance_modifier_instance_tfm(mmd, elem_idx, mat);
+
+ /* add object to cache */
+ newob = MEM_dupallocN(ob);
+ mul_m4_m4m4(newob->obmat, ob->obmat, mat);
+
+ /* apply scale */
+ ARRAY_SET_ITEMS(newob->size, mat[0][0], mat[1][1], mat[2][2]);
+
+ /* apply shift */
+ sh = x;
+ if (mmd->lock_axis == GP_LOCKAXIS_Y) {
+ sh = y;
+ }
+ if (mmd->lock_axis == GP_LOCKAXIS_Z) {
+ sh = z;
+ }
+ madd_v3_v3fl(newob->obmat[3], mmd->shift, sh);
+
+ /* add temp object to cache */
+ stl->g_data->gp_object_cache = gpencil_object_cache_add(
+ stl->g_data->gp_object_cache, newob, true,
+ &stl->g_data->gp_cache_size, &stl->g_data->gp_cache_used);
+ }
+ }
+ }
+}
+
+/* create instances using instance modifiers */
+void gpencil_instance_modifiers(GPENCIL_StorageList *stl, Object *ob)
+{
+ if ((ob) && (ob->data)) {
+ bGPdata *gpd = ob->data;
+ if (GPENCIL_ANY_EDIT_MODE(gpd)) {
+ return;
+ }
+ }
+
+ for (GpencilModifierData *md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (((md->mode & eGpencilModifierMode_Realtime) && (stl->storage->is_render == false)) ||
+ ((md->mode & eGpencilModifierMode_Render) && (stl->storage->is_render == true)))
+ {
+ if (md->type == eGpencilModifierType_Instance) {
+ InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md;
+
+ /* Only add instances if the "Make Objects" flag is set
+ * FIXME: This is a workaround for z-ordering weirdness when all instances are in the same object
+ */
+ if (mmd->flag & GP_INSTANCE_MAKE_OBJECTS) {
+ gp_instance_modifier_make_instances(stl, ob, mmd);
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
new file mode 100644
index 00000000000..71c99b2bcdf
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -0,0 +1,794 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ */
+
+/** \file blender/draw/engines/gpencil/gpencil_engine.c
+ * \ingroup draw
+ */
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BKE_camera.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_gpencil.h"
+#include "BKE_shader_fx.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_view3d_types.h"
+
+#include "draw_mode_engines.h"
+
+#include "UI_resources.h"
+
+#include "GPU_texture.h"
+
+#include "gpencil_engine.h"
+
+#include "ED_screen.h"
+#include "ED_gpencil.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[];
+
+/* *********** STATIC *********** */
+static GPENCIL_e_data e_data = {NULL}; /* Engine data */
+
+/* *********** FUNCTIONS *********** */
+
+/* create a multisample buffer if not present */
+void DRW_gpencil_multisample_ensure(GPENCIL_Data *vedata, int rect_w, int rect_h)
+{
+ 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)
+ });
+ if (!GPU_framebuffer_check_valid(fbl->multisample_fb, NULL)) {
+ GPU_framebuffer_free(fbl->multisample_fb);
+ }
+ }
+ }
+ }
+}
+
+static void GPENCIL_create_framebuffers(void *vedata)
+{
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+
+ /* Go full 32bits for rendering */
+ GPUTextureFormat 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 multiframe framebuffer for AA */
+ if (stl->storage->multisamples > 0) {
+ DRW_gpencil_multisample_ensure(vedata, size[0], size[1]);
+ }
+
+ /* temp textures */
+ e_data.temp_depth_tx_a = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8,
+ &draw_engine_gpencil_type);
+ e_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(e_data.temp_depth_tx_a),
+ GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_a)
+ });
+
+ e_data.temp_depth_tx_b = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8,
+ &draw_engine_gpencil_type);
+ e_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(e_data.temp_depth_tx_b),
+ GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_b)
+ });
+
+ /* used for rim FX effect */
+ e_data.temp_depth_tx_rim = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8,
+ &draw_engine_gpencil_type);
+ e_data.temp_color_tx_rim = DRW_texture_pool_query_2D(size[0], size[1], fb_format,
+ &draw_engine_gpencil_type);
+ GPU_framebuffer_ensure_config(&fbl->temp_fb_rim, {
+ GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_rim),
+ GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_rim),
+ });
+
+ /* background framebuffer to speed up drawing process (always 16 bits) */
+ e_data.background_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8,
+ &draw_engine_gpencil_type);
+ e_data.background_color_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA32F,
+ &draw_engine_gpencil_type);
+ GPU_framebuffer_ensure_config(&fbl->background_fb, {
+ GPU_ATTACHMENT_TEXTURE(e_data.background_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.background_color_tx)
+ });
+ }
+}
+
+static void GPENCIL_create_shaders(void)
+{
+ /* normal fill shader */
+ if (!e_data.gpencil_fill_sh) {
+ e_data.gpencil_fill_sh = DRW_shader_create(
+ datatoc_gpencil_fill_vert_glsl, NULL,
+ datatoc_gpencil_fill_frag_glsl, NULL);
+ }
+
+ /* normal stroke shader using geometry to display lines (line mode) */
+ if (!e_data.gpencil_stroke_sh) {
+ e_data.gpencil_stroke_sh = DRW_shader_create(
+ datatoc_gpencil_stroke_vert_glsl,
+ datatoc_gpencil_stroke_geom_glsl,
+ datatoc_gpencil_stroke_frag_glsl,
+ NULL);
+ }
+
+ /* dot/rectangle mode for normal strokes using geometry */
+ if (!e_data.gpencil_point_sh) {
+ e_data.gpencil_point_sh = DRW_shader_create(
+ datatoc_gpencil_point_vert_glsl,
+ datatoc_gpencil_point_geom_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(
+ datatoc_gpencil_edit_point_vert_glsl,
+ datatoc_gpencil_edit_point_geom_glsl,
+ datatoc_gpencil_edit_point_frag_glsl, NULL);
+ }
+
+ /* used for edit lines for edit modes */
+ if (!e_data.gpencil_line_sh) {
+ e_data.gpencil_line_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_FLAT_COLOR);
+ }
+
+ /* 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);
+ }
+
+ /* 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);
+ }
+
+ /* 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 (!e_data.gpencil_paper_sh) {
+ e_data.gpencil_paper_sh = DRW_shader_create_fullscreen(datatoc_gpencil_paper_frag_glsl, NULL);
+ }
+}
+
+void GPENCIL_engine_init(void *vedata)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ /* init storage */
+ if (!stl->storage) {
+ stl->storage = MEM_callocN(sizeof(GPENCIL_Storage), "GPENCIL_Storage");
+
+ /* unit matrix */
+ unit_m4(stl->storage->unit_matrix);
+ }
+
+ stl->storage->multisamples = U.gpencil_multisamples;
+
+ /* create framebuffers */
+ GPENCIL_create_framebuffers(vedata);
+
+ /* create shaders */
+ GPENCIL_create_shaders();
+ GPENCIL_create_fx_shaders(&e_data);
+
+ /* blank texture used if no texture defined for fill shader */
+ if (!e_data.gpencil_blank_texture) {
+ float rect[16][16][4] = {{{0.0f}}};
+ e_data.gpencil_blank_texture = DRW_texture_create_2D(16, 16, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect);
+ }
+}
+
+static void GPENCIL_engine_free(void)
+{
+ /* 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_fullscreen_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_simple_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);
+}
+
+void GPENCIL_cache_init(void *vedata)
+{
+ 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;
+
+ /* 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;
+ gp_style = BKE_material_gpencil_settings_get(obact, obact->actcol);
+ }
+
+ 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 */
+ }
+ stl->storage->tonemapping = 0;
+
+ stl->g_data->shgrps_edit_line = NULL;
+ stl->g_data->shgrps_edit_point = NULL;
+
+ if (!stl->shgroups) {
+ /* Alloc maximum size because count strokes is very slow and can be very complex due onion skinning.
+ I tried to allocate only one block and using realloc, increasing the size when read a new strokes
+ in cache_finish, but the realloc produce weird things on screen, so we keep as is while we found
+ a better solution
+ */
+ stl->shgroups = MEM_mallocN(sizeof(GPENCIL_shgroup) * GPENCIL_MAX_SHGROUPS, "GPENCIL_shgroup");
+ }
+
+ /* 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;
+
+ {
+ /* Stroke pass */
+ psl->stroke_pass = DRW_pass_create(
+ "GPencil Stroke Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND);
+ stl->storage->shgroup_id = 0;
+
+ /* edit pass */
+ psl->edit_pass = DRW_pass_create(
+ "GPencil Edit Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
+
+ /* detect if playing animation */
+ stl->storage->playing = 0;
+ if (draw_ctx->evil_C) {
+ stl->storage->playing = ED_screen_animation_playing(CTX_wm_manager(draw_ctx->evil_C)) != NULL ? 1 : 0;
+ }
+
+ 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->playing == 1) {
+ 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;
+ }
+ }
+
+ /* save render state */
+ stl->storage->is_render = DRW_state_is_image_render();
+ stl->storage->is_mat_preview = (bool)stl->storage->is_render && STREQ(scene->id.name + 2, "preview");
+
+ /* save simplify flags (can change while drawing, so it's better to save) */
+ stl->storage->simplify_fill = GP_SIMPLIFY_FILL(scene, stl->storage->playing);
+ stl->storage->simplify_modif = GP_SIMPLIFY_MODIF(scene, stl->storage->playing);
+
+ /* 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;
+ }
+
+ /* detect if painting session */
+ if ((obact_gpd) &&
+ (obact_gpd->flag & GP_DATA_STROKE_PAINTMODE) &&
+ (stl->storage->playing == 0))
+ {
+ if (((obact_gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) &&
+ (obact_gpd->runtime.sbuffer_size > 1))
+ {
+ 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;
+ }
+
+ 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;
+ }
+ }
+ }
+ else {
+ stl->storage->stroke_style = GP_STYLE_STROKE_STYLE_SOLID;
+ stl->storage->color_type = GPENCIL_COLOR_SOLID;
+ }
+
+ /* drawing buffer pass for drawing the stroke that is beeing 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 | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+
+ /* 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 | 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_add(mix_shgrp, quad, NULL);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeColor", &e_data.input_color_tx);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeDepth", &e_data.input_depth_tx);
+ DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1);
+
+ /* mix pass no blend used to copy between passes. A separated pass is required
+ * because if mix_pass is used, the acumulation 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_add(mix_shgrp_noblend, quad, NULL);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp_noblend, "strokeColor", &e_data.input_color_tx);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp_noblend, "strokeDepth", &e_data.input_depth_tx);
+ DRW_shgroup_uniform_int(mix_shgrp_noblend, "tonemapping", &stl->storage->tonemapping, 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 | 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_add(background_shgrp, quad, NULL);
+ DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeColor", &e_data.background_color_tx);
+ DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeDepth", &e_data.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);
+ DRWShadingGroup *paper_shgrp = DRW_shgroup_create(e_data.gpencil_paper_sh, psl->paper_pass);
+ DRW_shgroup_call_add(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);
+ }
+
+ /* grid pass */
+ if (v3d) {
+ psl->grid_pass = DRW_pass_create(
+ "GPencil Grid Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ stl->g_data->shgrps_grid = DRW_shgroup_create(e_data.gpencil_line_sh, psl->grid_pass);
+ }
+
+ /* create effects passes */
+ GPENCIL_create_fx_passes(psl);
+ }
+}
+
+void GPENCIL_cache_populate(void *vedata, Object *ob)
+{
+ /* object must be visible */
+ if (!DRW_check_object_visible_within_active_context(ob)) {
+ 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;
+
+ /* object datablock (this is not draw now) */
+ if (ob->type == OB_GPENCIL && ob->data) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if ((stl->g_data->session_flag & GP_DRW_PAINT_READY) == 0) {
+
+ /* if render set as dirty */
+ if (stl->storage->is_render == true) {
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
+
+ /* allocate memory for saving gp objects for drawing later */
+ stl->g_data->gp_object_cache = gpencil_object_cache_add(stl->g_data->gp_object_cache, ob, false,
+ &stl->g_data->gp_cache_size, &stl->g_data->gp_cache_used);
+
+ /* generate instances as separate cache objects for instance modifiers
+ * with the "Make as Objects" option enabled
+ */
+ if (!stl->storage->simplify_modif) {
+ gpencil_instance_modifiers(stl, ob);
+ }
+ }
+ /* draw current painting strokes */
+ DRW_gpencil_populate_buffer_strokes(&e_data, vedata, ts, ob);
+
+ /* grid */
+ if ((v3d) &&
+ ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (v3d->flag3 & V3D_GP_SHOW_GRID) &&
+ (ob->type == OB_GPENCIL) && (ob == draw_ctx->obact))
+ {
+ stl->g_data->batch_grid = DRW_gpencil_get_grid();
+ DRW_shgroup_call_add(stl->g_data->shgrps_grid,
+ stl->g_data->batch_grid,
+ ob->obmat);
+ }
+ }
+}
+
+void GPENCIL_cache_finish(void *vedata)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ bool is_multiedit = false;
+
+ /* if painting session, don't need to do more */
+ if (stl->g_data->session_flag & GP_DRW_PAINT_PAINTING) {
+ return;
+ }
+
+ /* Draw all pending objects */
+ if (stl->g_data->gp_cache_used > 0) {
+ for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
+ Object *ob = stl->g_data->gp_object_cache[i].ob;
+ bGPdata *gpd = ob->data;
+
+ /* save init shading group */
+ stl->g_data->gp_object_cache[i].init_grp = stl->storage->shgroup_id;
+
+ /* fill shading groups */
+ is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ if (!is_multiedit) {
+ DRW_gpencil_populate_datablock(&e_data, vedata, scene, ob, gpd);
+ }
+ else {
+ DRW_gpencil_populate_multiedit(&e_data, vedata, scene, ob, gpd);
+ }
+
+ /* save end shading group */
+ stl->g_data->gp_object_cache[i].end_grp = stl->storage->shgroup_id - 1;
+ /* if render set to dirty to refresh viewport */
+ if (stl->storage->is_render == true) {
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
+ /* FX passses */
+ tGPencilObjectCache *cache = &stl->g_data->gp_object_cache[i];
+ if (!is_multiedit) {
+ DRW_gpencil_fx_prepare(&e_data, vedata, cache);
+ }
+ }
+ }
+}
+
+/* helper function to sort inverse gpencil objects using qsort */
+static int gpencil_object_cache_compare_zdepth(const void *a1, const void *a2)
+{
+ const tGPencilObjectCache *ps1 = a1, *ps2 = a2;
+
+ if (ps1->zdepth < ps2->zdepth) return 1;
+ else if (ps1->zdepth > ps2->zdepth) return -1;
+
+ 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(fbl->background_fb, clearcol, 1.0f);
+ stl->g_data->session_flag = GP_DRW_PAINT_FILLING;
+ }
+ /* repeat pass to fill temp texture */
+ DRW_draw_pass(pass);
+ /* set default framebuffer again */
+ GPU_framebuffer_bind(dfbl->default_fb);
+ }
+}
+
+static void gpencil_free_obj_list(GPENCIL_StorageList *stl)
+{
+ /* Clear temp objects created for display instances only. These objects are created
+ * while the draw manager draw the scene, but only to hold the strokes data.
+ * see: gp_instance_modifier_make_instances()
+ *
+ * the normal objects are not freed because they are not tagged as temp objects
+ */
+ for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
+ Object *ob = stl->g_data->gp_object_cache[i].ob;
+ if (stl->g_data->gp_object_cache[i].temp_ob) {
+ MEM_SAFE_FREE(ob);
+ }
+ }
+
+ /* free the cache itself */
+ MEM_SAFE_FREE(stl->g_data->gp_object_cache);
+}
+
+/* draw scene */
+void GPENCIL_draw_scene(void *ved)
+{
+ 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;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
+
+ int init_grp, end_grp;
+ tGPencilObjectCache *cache;
+ 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 = (bool)stl->storage->playing;
+ const bool is_render = stl->storage->is_render;
+
+ /* paper pass to display a confortable area to draw over complex scenes with geometry */
+ if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
+ if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (v3d->flag3 & V3D_GP_SHOW_PAPER) &&
+ (stl->g_data->gp_cache_used > 0))
+ {
+ DRW_draw_pass(psl->paper_pass);
+ }
+ }
+
+ /* 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);
+
+ MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
+
+ DRW_draw_pass(psl->background_pass);
+ DRW_draw_pass(psl->drawing_pass);
+
+ MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, dfbl->default_fb, txl);
+
+ /* free memory */
+ gpencil_free_obj_list(stl);
+
+ /* grid pass */
+ if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
+ if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (v3d->flag3 & V3D_GP_SHOW_GRID))
+ {
+ DRW_draw_pass(psl->grid_pass);
+ }
+ }
+
+ return;
+ }
+
+ if (DRW_state_is_fbo()) {
+ /* attach temp textures */
+ GPU_framebuffer_texture_attach(fbl->temp_fb_a, e_data.temp_depth_tx_a, 0, 0);
+ GPU_framebuffer_texture_attach(fbl->temp_fb_a, e_data.temp_color_tx_a, 0, 0);
+ GPU_framebuffer_texture_attach(fbl->temp_fb_b, e_data.temp_depth_tx_b, 0, 0);
+ GPU_framebuffer_texture_attach(fbl->temp_fb_b, e_data.temp_color_tx_b, 0, 0);
+
+ GPU_framebuffer_texture_attach(fbl->background_fb, e_data.background_depth_tx, 0, 0);
+ GPU_framebuffer_texture_attach(fbl->background_fb, e_data.background_color_tx, 0, 0);
+
+ /* 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 = &stl->g_data->gp_object_cache[i];
+ Object *ob = cache->ob;
+ bGPdata *gpd = ob->data;
+ init_grp = cache->init_grp;
+ end_grp = cache->end_grp;
+ /* Render stroke in separated framebuffer */
+ GPU_framebuffer_bind(fbl->temp_fb_a);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
+
+ /* Stroke Pass: DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH
+ * draw only a subset that usually start with a fill and end with stroke because the
+ * shading groups are created by pairs */
+ if (end_grp >= init_grp) {
+ MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
+
+ DRW_draw_pass_subset(
+ psl->stroke_pass,
+ stl->shgroups[init_grp].shgrps_fill != NULL ?
+ stl->shgroups[init_grp].shgrps_fill : stl->shgroups[init_grp].shgrps_stroke,
+ stl->shgroups[end_grp].shgrps_stroke);
+
+ MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fbl->temp_fb_a, txl);
+ }
+
+ /* Current buffer drawing */
+ if ((!is_render) && (gpd->runtime.sbuffer_size > 0)) {
+ DRW_draw_pass(psl->drawing_pass);
+ }
+ /* fx passes */
+ if (BKE_shaderfx_has_gpencil(ob)) {
+ stl->storage->tonemapping = 0;
+ DRW_gpencil_fx_draw(&e_data, vedata, cache);
+ }
+
+ e_data.input_depth_tx = e_data.temp_depth_tx_a;
+ e_data.input_color_tx = e_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 = stl->storage->is_render ? 1 : 0;
+
+ DRW_draw_pass(psl->mix_pass);
+
+ /* prepare for fast drawing */
+ if (!is_render) {
+ gpencil_prepare_fast_drawing(stl, dfbl, fbl, psl->mix_pass_noblend, clearcol);
+ }
+ }
+ /* edit points */
+ if ((!is_render) && (!playing)) {
+ DRW_draw_pass(psl->edit_pass);
+ }
+ }
+ /* grid pass */
+ if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
+ if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (v3d->flag3 & V3D_GP_SHOW_GRID))
+ {
+ DRW_draw_pass(psl->grid_pass);
+ }
+ }
+ }
+ /* free memory */
+ gpencil_free_obj_list(stl);
+
+ /* detach temp textures */
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_texture_detach(fbl->temp_fb_a, e_data.temp_depth_tx_a);
+ GPU_framebuffer_texture_detach(fbl->temp_fb_a, e_data.temp_color_tx_a);
+ GPU_framebuffer_texture_detach(fbl->temp_fb_b, e_data.temp_depth_tx_b);
+ GPU_framebuffer_texture_detach(fbl->temp_fb_b, e_data.temp_color_tx_b);
+
+ GPU_framebuffer_texture_detach(fbl->background_fb, e_data.background_depth_tx);
+ GPU_framebuffer_texture_detach(fbl->background_fb, e_data.background_color_tx);
+
+ /* attach again default framebuffer after detach textures */
+ if (!is_render) {
+ GPU_framebuffer_bind(dfbl->default_fb);
+ }
+
+ /* 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;
+ }
+ }
+}
+
+static const DrawEngineDataSize GPENCIL_data_size = DRW_VIEWPORT_DATA_SIZE(GPENCIL_Data);
+
+DrawEngineType draw_engine_gpencil_type = {
+ NULL, NULL,
+ N_("GpencilMode"),
+ &GPENCIL_data_size,
+ &GPENCIL_engine_init,
+ &GPENCIL_engine_free,
+ &GPENCIL_cache_init,
+ &GPENCIL_cache_populate,
+ &GPENCIL_cache_finish,
+ NULL,
+ &GPENCIL_draw_scene,
+ NULL,
+ NULL,
+ &GPENCIL_render_to_image,
+};
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
new file mode 100644
index 00000000000..24a627f1012
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ */
+
+/** \file blender/draw/engines/gpencil/gpencil_engine.h
+ * \ingroup draw
+ */
+
+#ifndef __GPENCIL_ENGINE_H__
+#define __GPENCIL_ENGINE_H__
+
+#include "GPU_batch.h"
+
+struct tGPspoint;
+struct bGPDstroke;
+struct ModifierData;
+struct GPENCIL_Data;
+struct GPENCIL_StorageList;
+struct Object;
+struct MaterialGPencilStyle;
+struct RenderEngine;
+struct RenderLayer;
+
+ /* TODO: these could be system parameter in userprefs screen */
+#define GPENCIL_MAX_GP_OBJ 256
+
+#define GPENCIL_CACHE_BLOCK_SIZE 8
+#define GPENCIL_MAX_SHGROUPS 65536
+#define GPENCIL_MIN_BATCH_SLOTS_CHUNK 16
+
+#define GPENCIL_COLOR_SOLID 0
+#define GPENCIL_COLOR_TEXTURE 1
+#define GPENCIL_COLOR_PATTERN 2
+
+#define GP_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE))
+#define GP_SIMPLIFY_ONPLAY(playing) (((playing == true) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ON_PLAY)) || ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ON_PLAY) == 0))
+#define GP_SIMPLIFY_FILL(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FILL)))
+#define GP_SIMPLIFY_MODIF(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_MODIFIER)))
+
+#define GP_IS_CAMERAVIEW ((rv3d != NULL) && (rv3d->persp == RV3D_CAMOB && v3d->camera))
+
+ /* *********** OBJECTS CACHE *********** */
+
+ /* used to save gpencil objects */
+typedef struct tGPencilObjectCache {
+ struct Object *ob;
+ int init_grp, end_grp;
+ int idx; /*original index, can change after sort */
+
+ /* effects */
+ DRWShadingGroup *fx_wave_sh;
+ DRWShadingGroup *fx_blur_sh;
+ DRWShadingGroup *fx_colorize_sh;
+ DRWShadingGroup *fx_pixel_sh;
+ DRWShadingGroup *fx_rim_sh;
+ DRWShadingGroup *fx_swirl_sh;
+ DRWShadingGroup *fx_flip_sh;
+ DRWShadingGroup *fx_light_sh;
+
+ float zdepth; /* z-depth value to sort gp object */
+ bool temp_ob; /* flag to tag temporary objects that must be removed after drawing loop */
+} tGPencilObjectCache;
+
+ /* *********** 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;
+ float obj_scale;
+ struct DRWShadingGroup *shgrps_fill;
+ struct DRWShadingGroup *shgrps_stroke;
+} GPENCIL_shgroup;
+
+typedef struct GPENCIL_Storage {
+ int shgroup_id; /* total elements */
+ float unit_matrix[4][4];
+ int stroke_style;
+ int color_type;
+ int mode;
+ int xray;
+ int keep_size;
+ float obj_scale;
+ float pixfactor;
+ int playing;
+ bool is_render;
+ bool is_mat_preview;
+ const float *pixsize;
+ float render_pixsize;
+ int tonemapping;
+ short multisamples;
+
+ /* simplify settings*/
+ bool simplify_fill;
+ bool simplify_modif;
+ bool simplify_fx;
+
+ /* Render Matrices and data */
+ float persmat[4][4], persinv[4][4];
+ float viewmat[4][4], viewinv[4][4];
+ float winmat[4][4], wininv[4][4];
+ float view_vecs[2][4]; /* vec4[2] */
+
+ Object *camera; /* camera pointer for render mode */
+} GPENCIL_Storage;
+
+typedef struct GPENCIL_StorageList {
+ struct GPENCIL_Storage *storage;
+ struct g_data *g_data;
+ struct GPENCIL_shgroup *shgroups;
+} GPENCIL_StorageList;
+
+typedef struct GPENCIL_PassList {
+ struct DRWPass *stroke_pass;
+ 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;
+
+ /* effects */
+ struct DRWPass *fx_shader_pass;
+ struct DRWPass *fx_shader_pass_blend;
+
+} GPENCIL_PassList;
+
+typedef struct GPENCIL_FramebufferList {
+ struct GPUFrameBuffer *main;
+ struct GPUFrameBuffer *temp_fb_a;
+ struct GPUFrameBuffer *temp_fb_b;
+ struct GPUFrameBuffer *temp_fb_rim;
+ struct GPUFrameBuffer *background_fb;
+
+ struct GPUFrameBuffer *multisample_fb;
+} GPENCIL_FramebufferList;
+
+typedef struct GPENCIL_TextureList {
+ struct GPUTexture *texture;
+
+ /* multisample textures */
+ struct GPUTexture *multisample_color;
+ struct GPUTexture *multisample_depth;
+
+} GPENCIL_TextureList;
+
+typedef struct GPENCIL_Data {
+ void *engine_type; /* Required */
+ struct GPENCIL_FramebufferList *fbl;
+ 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;
+
+ /* for buffer only one batch is nedeed because the drawing is only of one stroke */
+ GPUBatch *batch_buffer_stroke;
+ GPUBatch *batch_buffer_fill;
+
+ /* grid geometry */
+ GPUBatch *batch_grid;
+
+ int gp_cache_used; /* total objects in cache */
+ int gp_cache_size; /* size of the cache */
+ struct tGPencilObjectCache *gp_object_cache;
+
+ int session_flag;
+
+} 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 {
+ /* 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_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_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_swirl_sh;
+ struct GPUShader *gpencil_fx_wave_sh;
+
+ /* textures */
+ struct GPUTexture *background_depth_tx;
+ struct GPUTexture *background_color_tx;
+
+ struct GPUTexture *gpencil_blank_texture;
+
+ /* 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_rim;
+ struct GPUTexture *temp_depth_tx_rim;
+} GPENCIL_e_data; /* Engine data */
+
+/* GPUBatch Cache */
+typedef struct GpencilBatchCache {
+ /* For normal strokes, a variable number of batch can be needed depending of number of strokes.
+ It could use the stroke number as total size, but when activate the onion skining, the number
+ can change, so the size is changed dinamically.
+ */
+ GPUBatch **batch_stroke;
+ GPUBatch **batch_fill;
+ GPUBatch **batch_edit;
+ GPUBatch **batch_edlin;
+
+ /* settings to determine if cache is invalid */
+ bool is_dirty;
+ bool is_editmode;
+ int cache_frame;
+
+ /* keep information about the size of the cache */
+ int cache_size; /* total batch slots available */
+ int cache_idx; /* current slot index */
+} GpencilBatchCache;
+
+/* general drawing functions */
+struct DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata, struct DRWPass *pass, struct GPUShader *shader,
+ struct Object *ob, struct bGPdata *gpd, struct MaterialGPencilStyle *gp_style, int id, bool onion);
+void DRW_gpencil_populate_datablock(struct GPENCIL_e_data *e_data, void *vedata, struct Scene *scene, struct Object *ob, struct bGPdata *gpd);
+void DRW_gpencil_populate_buffer_strokes(struct GPENCIL_e_data *e_data, void *vedata, struct ToolSettings *ts, struct Object *ob);
+void DRW_gpencil_populate_multiedit(struct GPENCIL_e_data *e_data, void *vedata, struct Scene *scene, struct Object *ob, struct bGPdata *gpd);
+void DRW_gpencil_triangulate_stroke_fill(struct bGPDstroke *gps);
+
+void DRW_gpencil_multisample_ensure(struct GPENCIL_Data *vedata, int rect_w, int rect_h);
+
+/* create geometry functions */
+struct GPUBatch *DRW_gpencil_get_point_geom(struct bGPDstroke *gps, short thickness, const float ink[4]);
+struct GPUBatch *DRW_gpencil_get_stroke_geom(struct bGPDframe *gpf, struct bGPDstroke *gps, short thickness, const float ink[4]);
+struct GPUBatch *DRW_gpencil_get_fill_geom(struct Object *ob, struct bGPDstroke *gps, const float color[4]);
+struct GPUBatch *DRW_gpencil_get_edit_geom(struct bGPDstroke *gps, float alpha, short dflag);
+struct GPUBatch *DRW_gpencil_get_edlin_geom(struct bGPDstroke *gps, float alpha, short dflag);
+struct GPUBatch *DRW_gpencil_get_buffer_stroke_geom(struct bGPdata *gpd, float matrix[4][4], short thickness);
+struct GPUBatch *DRW_gpencil_get_buffer_fill_geom(struct bGPdata *gpd);
+struct GPUBatch *DRW_gpencil_get_buffer_point_geom(struct bGPdata *gpd, float matrix[4][4], short thickness);
+struct GPUBatch *DRW_gpencil_get_grid(void);
+
+/* object cache functions */
+struct tGPencilObjectCache *gpencil_object_cache_add(struct tGPencilObjectCache *cache_array, struct Object *ob,
+ bool is_temp, int *gp_cache_size, int *gp_cache_used);
+
+/* geometry batch cache functions */
+void gpencil_batch_cache_check_free_slots(struct Object *ob);
+struct GpencilBatchCache *gpencil_batch_cache_get(struct Object *ob, int cfra);
+
+/* modifier functions */
+void gpencil_instance_modifiers(struct GPENCIL_StorageList *stl, struct Object *ob);
+
+/* 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);
+
+void DRW_gpencil_fx_prepare(
+ struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata,
+ struct tGPencilObjectCache *cache);
+void DRW_gpencil_fx_draw(
+ struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata,
+ struct tGPencilObjectCache *cache);
+
+/* main functions */
+void GPENCIL_engine_init(void *vedata);
+void GPENCIL_cache_init(void *vedata);
+void GPENCIL_cache_populate(void *vedata, struct Object *ob);
+void GPENCIL_cache_finish(void *vedata);
+void GPENCIL_draw_scene(void *vedata);
+
+/* render */
+void GPENCIL_render_init(struct GPENCIL_Data *ved, struct RenderEngine *engine, struct Depsgraph *depsgraph);
+void GPENCIL_render_to_image(void *vedata, struct RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect);
+
+/* Use of multisample framebuffers. */
+#define MULTISAMPLE_GP_SYNC_ENABLE(lvl, fbl) { \
+ if ((lvl > 0) && (fbl->multisample_fb != NULL)) { \
+ DRW_stats_query_start("GP Multisample Blit"); \
+ GPU_framebuffer_bind(fbl->multisample_fb); \
+ GPU_framebuffer_clear_color_depth(fbl->multisample_fb, (const float[4]){0.0f}, 1.0f); \
+ DRW_stats_query_end(); \
+ } \
+}
+
+#define MULTISAMPLE_GP_SYNC_DISABLE(lvl, fbl, fb, txl) { \
+ if ((lvl > 0) && (fbl->multisample_fb != NULL)) { \
+ DRW_stats_query_start("GP Multisample Resolve"); \
+ GPU_framebuffer_bind(fb); \
+ DRW_multisamples_resolve(txl->multisample_depth, txl->multisample_color, true); \
+ DRW_stats_query_end(); \
+ } \
+}
+
+#endif /* __GPENCIL_ENGINE_H__ */
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
new file mode 100644
index 00000000000..d76ea56894f
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ */
+
+/** \file blender/draw/engines/gpencil/gpencil_render.c
+ * \ingroup draw
+ */
+#include "BLI_rect.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BKE_camera.h"
+
+#include "DNA_gpencil_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "draw_mode_engines.h"
+
+#include "RE_pipeline.h"
+
+#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)
+{
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_StorageList *stl = vedata->stl;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+
+ 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 multiframe framebuffer for AA */
+ if (U.gpencil_multisamples > 0) {
+ int rect_w = (int)viewport_size[0];
+ int rect_h = (int)viewport_size[1];
+ DRW_gpencil_multisample_ensure(vedata, rect_w, rect_h);
+ }
+
+ vedata->render_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8,
+ &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. */
+ struct Object *camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
+ float frame = BKE_scene_frame_get(scene);
+ RE_GetCameraWindow(engine->re, camera, frame, stl->storage->winmat);
+ RE_GetCameraModelMatrix(engine->re, camera, stl->storage->viewinv);
+
+ invert_m4_m4(stl->storage->viewmat, stl->storage->viewinv);
+ mul_m4_m4m4(stl->storage->persmat, stl->storage->winmat, stl->storage->viewmat);
+ invert_m4_m4(stl->storage->persinv, stl->storage->persmat);
+ invert_m4_m4(stl->storage->wininv, stl->storage->winmat);
+
+ DRW_viewport_matrix_override_set(stl->storage->persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(stl->storage->persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(stl->storage->winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_override_set(stl->storage->wininv, DRW_MAT_WININV);
+ DRW_viewport_matrix_override_set(stl->storage->viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_override_set(stl->storage->viewinv, DRW_MAT_VIEWINV);
+
+ /* calculate pixel size for render */
+ stl->storage->render_pixsize = get_render_pixelsize(stl->storage->persmat, viewport_size[0], viewport_size[1]);
+ /* INIT CACHE */
+ GPENCIL_cache_init(vedata);
+}
+
+/* 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))
+{
+ if ((ob == NULL) || (DRW_check_object_visible_within_active_context(ob) == false)) {
+ return;
+ }
+
+ if (ob->type == OB_GPENCIL) {
+ 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], 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_viewport_matrix_get(winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_get(invproj, DRW_MAT_WININV);
+
+ /* 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, const rcti *rect)
+{
+ 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, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), rp->rect);
+
+ bool is_persp = DRW_viewport_is_persp_get();
+
+ GPENCIL_render_update_vecs(vedata);
+
+ /* 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) {
+ rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
+ rp->rect[i] = stl->storage->winmat[3][2] / (rp->rect[i] + stl->storage->winmat[2][2]);
+ }
+ else {
+ rp->rect[i] = -stl->storage->view_vecs[0][2] + rp->rect[i] * -stl->storage->view_vecs[1][2];
+ }
+ }
+ }
+ }
+}
+
+/* read combined render result */
+static void GPENCIL_render_result_combined(struct RenderLayer *rl, const char *viewname, GPENCIL_Data *vedata, const rcti *rect)
+{
+ 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, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 4, 0, rp->rect);
+}
+
+/* helper to blend pixels */
+static void blend_pixel(float src[4], float dst[4])
+{
+ float alpha = src[3];
+
+ /* use blend: GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA */
+ dst[0] = (src[0] * alpha) + (dst[0] * (1.0f - alpha));
+ dst[1] = (src[1] * alpha) + (dst[1] * (1.0f - alpha));
+ dst[2] = (src[2] * alpha) + (dst[2] * (1.0f - alpha));
+}
+
+/* render grease pencil to image */
+void GPENCIL_render_to_image(void *vedata, RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect)
+{
+ 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");
+ }
+
+ 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);
+
+ GPENCIL_cache_finish(vedata);
+ 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;
+ float tmp[4];
+
+ 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) {
+ copy_v4_v4(tmp, gp_pixel_rgba);
+ if (src_pixel_rgba[3] > 0.0f) {
+ /* copy source color on back */
+ copy_v4_v4(gp_pixel_rgba, src_pixel_rgba);
+ /* 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 gp render */
+ blend_pixel(tmp, gp_pixel_rgba);
+ /* blend object on top */
+ blend_pixel(src_pixel_rgba, gp_pixel_rgba);
+ }
+ else {
+ /* blend gp render */
+ blend_pixel(tmp, gp_pixel_rgba);
+ }
+ }
+ }
+ 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_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
new file mode 100644
index 00000000000..e453224020d
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
@@ -0,0 +1,848 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ */
+
+/** \file blender/draw/engines/gpencil/gpencil_shader_fx.c
+ * \ingroup draw
+ */
+#include "DNA_gpencil_types.h"
+#include "DNA_shader_fx_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_camera_types.h"
+
+#include "BKE_gpencil.h"
+#include "BKE_shader_fx.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BKE_camera.h"
+
+#include "ED_view3d.h"
+#include "ED_gpencil.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_swirl_frag_glsl[];
+extern char datatoc_gpencil_fx_wave_frag_glsl[];
+
+/* verify if this fx is active */
+static bool effect_is_active(Object *ob, ShaderFxData *fx, bool is_render)
+{
+ if (fx == NULL) {
+ return false;
+ }
+
+ bGPdata *gpd = ob->data;
+ if (gpd == NULL) {
+ return false;
+ }
+
+ bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
+ if (((fx->mode & eShaderFxMode_Editmode) == 0) && (is_edit)) {
+ return false;
+ }
+
+ if (((fx->mode & eShaderFxMode_Realtime) && (is_render == false)) ||
+ ((fx->mode & eShaderFxMode_Render) && (is_render == true)))
+ {
+ 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])
+{
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->flag & GP_LAYER_HIDE)
+ continue;
+
+ /* 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;
+ }
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ Camera *cam = (Camera *)camera->data;
+
+ float fstop = cam->gpu_dof.fstop;
+ float focus_dist = BKE_camera_object_dof_distance(camera);
+ float focal_len = cam->lens;
+
+ /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm
+ * unit.scale_length is how many meters per blender unit we have. We want to convert to blender units though
+ * because the shader reads coordinates in world space, which is in blender units.
+ * Note however that focus_distance is already in blender units and shall not be scaled here (see T48157). */
+ float scale = (scene->unit.system) ? scene->unit.scale_length : 1.0f;
+ float scale_camera = 0.001f / scale;
+ /* 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;
+
+ 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);
+}
+
+/* **************** 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 DRW_gpencil_fx_blur(
+ ShaderFxData *fx, int ob_idx, GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata, tGPencilObjectCache *cache)
+{
+ if (fx == NULL) {
+ 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;
+
+ Object *ob = cache->ob;
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ 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;
+ }
+ }
+
+ struct GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+
+ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh,
+ psl->fx_shader_pass_blend);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+ DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
+
+ DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &ob->loc[0], 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+}
+
+/* Colorize FX */
+static void DRW_gpencil_fx_colorize(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata)
+{
+ if (fx == NULL) {
+ return;
+ }
+ ColorizeShaderFxData *fxd = (ColorizeShaderFxData *)fx;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ DRWShadingGroup *fx_shgrp;
+
+ struct 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_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_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 DRW_gpencil_fx_flip(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata)
+{
+ if (fx == NULL) {
+ return;
+ }
+ 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;
+ }
+
+ struct 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_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+ DRW_shgroup_uniform_int(fx_shgrp, "flipmode", &fxd->flipmode, 1);
+
+ DRW_shgroup_uniform_vec2(fx_shgrp, "wsize", DRW_viewport_size_get(), 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+}
+
+/* Light FX */
+static void DRW_gpencil_fx_light(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata,
+ tGPencilObjectCache *cache)
+{
+ if (fx == NULL) {
+ return;
+ }
+ Object *ob = cache->ob;
+ 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;
+
+ struct 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_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_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->loc[0]);
+
+ /* 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 = (bGPdata *)ob->data;
+ if (!get_normal_vector(gpd, r_point, r_normal)) {
+ return;
+ }
+ mul_mat3_m4_v3(ob->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->loc, r_plane);
+ fxd->loc[3] = dt; /* use last element to save it */
+
+ DRW_shgroup_uniform_vec4(fx_shgrp, "loc", &fxd->loc[0], 1);
+
+ DRW_shgroup_uniform_float(fx_shgrp, "energy", &fxd->energy, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "ambient", &fxd->ambient, 1);
+
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+}
+
+/* Pixelate FX */
+static void DRW_gpencil_fx_pixel(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata,
+ tGPencilObjectCache *cache)
+{
+ if (fx == NULL) {
+ return;
+ }
+ Object *ob = cache->ob;
+ PixelShaderFxData *fxd = (PixelShaderFxData *)fx;
+
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ DRWShadingGroup *fx_shgrp;
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ fxd->size[2] = (int)fxd->flag & FX_PIXEL_USE_LINES;
+
+ struct 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_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_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", &ob->loc[0], 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+}
+
+/* Rim FX */
+static void DRW_gpencil_fx_rim(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata,
+ tGPencilObjectCache *cache)
+{
+ if (fx == NULL) {
+ return;
+ }
+ Object *ob = cache->ob;
+ RimShaderFxData *fxd = (RimShaderFxData *)fx;
+
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ DRWShadingGroup *fx_shgrp;
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ struct GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+ /* prepare pass */
+ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_rim_prepare_sh,
+ psl->fx_shader_pass_blend);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_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", &ob->loc[0], 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 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_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_rim);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_rim);
+ DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
+
+ DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &ob->loc[0], 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 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_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeRim", &e_data->temp_color_tx_rim);
+ 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;
+}
+
+/* Swirl FX */
+static void DRW_gpencil_fx_swirl(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata,
+ tGPencilObjectCache *cache)
+{
+ if (fx == NULL) {
+ return;
+ }
+ Object *ob = cache->ob;
+ SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
+ if (fxd->object == NULL) {
+ return;
+ }
+
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ DRWShadingGroup *fx_shgrp;
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ fxd->transparent = (int)fxd->flag & FX_SWIRL_MAKE_TRANSPARENT;
+
+ struct 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_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+
+ DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
+
+ DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &fxd->object->loc[0], 1);
+
+ 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);
+
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+}
+
+/* Wave Distorsion FX */
+static void DRW_gpencil_fx_wave(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata)
+{
+ if (fx == NULL) {
+ return;
+ }
+
+ WaveShaderFxData *fxd = (WaveShaderFxData *)fx;
+
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ struct 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_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_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);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+}
+
+/* ************************************************************** */
+
+/* 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);
+
+ e_data->gpencil_fx_rim_resolve_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_rim_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);
+ }
+}
+
+/* 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_swirl_sh);
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_wave_sh);
+}
+
+/* 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 |
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+}
+
+
+/* prepare fx shading groups */
+void DRW_gpencil_fx_prepare(
+ struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata,
+ struct tGPencilObjectCache *cache)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ Object *ob = cache->ob;
+ int ob_idx = cache->idx;
+
+ if (ob->shader_fx.first == NULL) {
+ return;
+ }
+ /* loop FX */
+ for (ShaderFxData *fx = ob->shader_fx.first; fx; fx = fx->next) {
+ if (effect_is_active(ob, fx, stl->storage->is_render)) {
+ switch (fx->type) {
+ case eShaderFxType_Blur:
+ DRW_gpencil_fx_blur(fx, ob_idx, e_data, vedata, cache);
+ break;
+ case eShaderFxType_Colorize:
+ DRW_gpencil_fx_colorize(fx, e_data, vedata);
+ break;
+ case eShaderFxType_Flip:
+ DRW_gpencil_fx_flip(fx, e_data, vedata);
+ break;
+ case eShaderFxType_Light:
+ DRW_gpencil_fx_light(fx, e_data, vedata, cache);
+ break;
+ case eShaderFxType_Pixel:
+ DRW_gpencil_fx_pixel(fx, e_data, vedata, cache);
+ break;
+ case eShaderFxType_Rim:
+ DRW_gpencil_fx_rim(fx, e_data, vedata, cache);
+ break;
+ case eShaderFxType_Swirl:
+ DRW_gpencil_fx_swirl(fx, e_data, vedata, cache);
+ break;
+ case eShaderFxType_Wave:
+ DRW_gpencil_fx_wave(fx, e_data, vedata);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+}
+
+/* helper to draw one FX pass and do ping-pong copy */
+static void gpencil_draw_fx_pass(
+ GPENCIL_e_data *e_data,
+ GPENCIL_PassList *psl,
+ GPENCIL_FramebufferList *fbl,
+ DRWShadingGroup *shgrp, bool blend)
+{
+ if (shgrp == NULL) {
+ return;
+ }
+
+ static float clearcol[4] = { 0.0f, 0.0f, 0.0f, 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 */
+ e_data->input_depth_tx = e_data->temp_depth_tx_b;
+ e_data->input_color_tx = e_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(
+ struct GPENCIL_e_data *e_data,
+ struct GPENCIL_Data *vedata,
+ struct BlurShaderFxData *fxd)
+{
+ if (fxd->runtime.fx_sh == NULL) {
+ return;
+ }
+
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+ 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(e_data, psl, fbl, shgrp, true);
+ }
+ /* vertical */
+ if (by > 0) {
+ fxd->blur[0] = 0;
+ fxd->blur[1] = by;
+ gpencil_draw_fx_pass(e_data, psl, fbl, shgrp, true);
+ }
+ }
+}
+
+static void draw_gpencil_rim_blur(
+ struct GPENCIL_e_data *UNUSED(e_data),
+ struct GPENCIL_Data *vedata,
+ struct RimShaderFxData *fxd)
+{
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+ static float clearcol[4] = { 0.0f, 0.0f, 0.0f, 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,
+ fxd->runtime.fx_sh_b, fxd->runtime.fx_sh_b);
+
+ /* copy pass from b for ping-pong frame buffers */
+ GPU_framebuffer_bind(fbl->temp_fb_rim);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_rim, clearcol, 1.0f);
+ DRW_draw_pass(psl->mix_pass_noblend);
+}
+
+/* helper to draw RIM passes */
+static void draw_gpencil_rim_passes(
+ struct GPENCIL_e_data *e_data,
+ struct GPENCIL_Data *vedata,
+ struct RimShaderFxData *fxd)
+{
+ if (fxd->runtime.fx_sh_b == NULL) {
+ return;
+ }
+
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+
+ static float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ int bx = fxd->blur[0];
+ int by = fxd->blur[1];
+
+ /* prepare mask */
+ GPU_framebuffer_bind(fbl->temp_fb_rim);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_rim, clearcol, 1.0f);
+ DRW_draw_pass_subset(
+ psl->fx_shader_pass_blend,
+ fxd->runtime.fx_sh, fxd->runtime.fx_sh);
+
+ /* blur rim */
+ e_data->input_depth_tx = e_data->temp_depth_tx_b;
+ e_data->input_color_tx = e_data->temp_color_tx_b;
+
+ if ((fxd->samples > 0) && ((bx > 0) || (by > 0))) {
+ for (int x = 0; x < fxd->samples; x++) {
+
+ /* horizontal */
+ fxd->blur[0] = bx;
+ fxd->blur[1] = 0;
+ draw_gpencil_rim_blur(e_data, vedata, fxd);
+
+ /* Vertical */
+ fxd->blur[0] = 0;
+ fxd->blur[1] = by;
+ draw_gpencil_rim_blur(e_data, vedata, fxd);
+
+ fxd->blur[0] = bx;
+ fxd->blur[1] = by;
+ }
+ }
+ /* 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 */
+ e_data->input_depth_tx = e_data->temp_depth_tx_b;
+ e_data->input_color_tx = e_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 DRW_gpencil_fx_draw(
+ struct GPENCIL_e_data *e_data,
+ struct GPENCIL_Data *vedata, struct tGPencilObjectCache *cache)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+ Object *ob = cache->ob;
+
+ /* loop FX modifiers */
+ for (ShaderFxData *fx = ob->shader_fx.first; fx; fx = fx->next) {
+ if (effect_is_active(ob, fx, stl->storage->is_render)) {
+ switch (fx->type) {
+ case eShaderFxType_Blur:
+ {
+ BlurShaderFxData *fxd = (BlurShaderFxData *)fx;
+ draw_gpencil_blur_passes(e_data, vedata, fxd);
+ break;
+ }
+ case eShaderFxType_Colorize:
+ {
+ ColorizeShaderFxData *fxd = (ColorizeShaderFxData *)fx;
+ gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false);
+ break;
+ }
+ case eShaderFxType_Flip:
+ {
+ FlipShaderFxData *fxd = (FlipShaderFxData *)fx;
+ gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false);
+ break;
+ }
+ case eShaderFxType_Light:
+ {
+ LightShaderFxData *fxd = (LightShaderFxData *)fx;
+ gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false);
+ break;
+ }
+ case eShaderFxType_Pixel:
+ {
+ PixelShaderFxData *fxd = (PixelShaderFxData *)fx;
+ gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false);
+ break;
+ }
+ case eShaderFxType_Rim:
+ {
+ RimShaderFxData *fxd = (RimShaderFxData *)fx;
+ draw_gpencil_rim_passes(e_data, vedata, fxd);
+ break;
+ }
+ case eShaderFxType_Swirl:
+ {
+ SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
+ gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false);
+ break;
+ }
+ case eShaderFxType_Wave:
+ {
+ WaveShaderFxData *fxd = (WaveShaderFxData *)fx;
+ gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+}
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
new file mode 100644
index 00000000000..1d66ba3d4d4
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl
@@ -0,0 +1,60 @@
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewMatrix;
+
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+
+uniform int blur[2];
+
+uniform vec3 loc;
+uniform float pixsize; /* rv3d->pixsize */
+uniform float pixelsize; /* U.pixelsize */
+uniform float pixfactor;
+
+float defaultpixsize = pixsize * pixelsize * (1000.0 / pixfactor);
+vec2 noffset = vec2(blur[0], blur[1]);
+
+out vec4 FragColor;
+
+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);
+
+ /* apply blurring, using a 9-tap filter with predefined gaussian weights */
+ /* depth */
+ float outdepth = 0;
+ outdepth += texelFetch(strokeDepth, ivec2(uv.x - 1.0 * dx, uv.y + 1.0 * dy), 0).r * 0.0947416;
+ outdepth += texelFetch(strokeDepth, ivec2(uv.x - 0.0 * dx, uv.y + 1.0 * dy), 0).r * 0.118318;
+ outdepth += texelFetch(strokeDepth, ivec2(uv.x + 1.0 * dx, uv.y + 1.0 * dy), 0).r * 0.0947416;
+ outdepth += texelFetch(strokeDepth, ivec2(uv.x - 1.0 * dx, uv.y + 0.0 * dy), 0).r * 0.118318;
+
+ outdepth += texelFetch(strokeDepth, ivec2(uv.x, uv.y), 0).r * 0.147761;
+
+ outdepth += texelFetch(strokeDepth, ivec2(uv.x + 1.0 * dx, uv.y + 0.0 * dy), 0).r * 0.118318;
+ outdepth += texelFetch(strokeDepth, ivec2(uv.x - 1.0 * dx, uv.y - 1.0 * dy), 0).r * 0.0947416;
+ outdepth += texelFetch(strokeDepth, ivec2(uv.x + 0.0 * dx, uv.y - 1.0 * dy), 0).r * 0.118318;
+ outdepth += texelFetch(strokeDepth, ivec2(uv.x + 1.0 * dx, uv.y - 1.0 * dy), 0).r * 0.0947416;
+
+ 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);
+}
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
new file mode 100644
index 00000000000..7d0ce4a804e
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl
@@ -0,0 +1,86 @@
+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_BITONE 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_BITONE:
+ {
+ 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
new file mode 100644
index 00000000000..94fb3405c79
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl
@@ -0,0 +1,37 @@
+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_light_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl
new file mode 100644
index 00000000000..f3026c32fc8
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl
@@ -0,0 +1,70 @@
+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 pixelsize; /* U.pixelsize */
+uniform float pixfactor;
+
+out vec4 FragColor;
+
+float defaultpixsize = pixsize * pixelsize * (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
new file mode 100644
index 00000000000..d1a57a9a1b6
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl
@@ -0,0 +1,50 @@
+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 pixelsize; /* U.pixelsize */
+uniform float pixfactor;
+
+out vec4 FragColor;
+
+int uselines = size[2];
+float defaultpixsize = pixsize * pixelsize * (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
new file mode 100644
index 00000000000..fe35d3832e1
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl
@@ -0,0 +1,64 @@
+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 pixelsize; /* U.pixelsize */
+uniform float pixfactor;
+
+float defaultpixsize = pixsize * pixelsize * (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
new file mode 100644
index 00000000000..5e5edbd8325
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl
@@ -0,0 +1,101 @@
+/* ******************************************************************* */
+/* 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_swirl_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl
new file mode 100644
index 00000000000..6ce64350b3d
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl
@@ -0,0 +1,70 @@
+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 pixelsize; /* U.pixelsize */
+uniform float pixfactor;
+
+out vec4 FragColor;
+
+float defaultpixsize = pixsize * pixelsize * (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 pxradius = (ProjectionMatrix[3][3] == 0.0) ? (radius / (loc.z * defaultpixsize)) : (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
new file mode 100644
index 00000000000..882b2cf59f1
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl
@@ -0,0 +1,40 @@
+
+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;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl
new file mode 100644
index 00000000000..cbd7a461dd3
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl
@@ -0,0 +1,12 @@
+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_edit_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl
new file mode 100644
index 00000000000..b3bd8e488f2
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl
@@ -0,0 +1,17 @@
+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
new file mode 100644
index 00000000000..0d2da00db66
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl
@@ -0,0 +1,48 @@
+uniform mat4 ModelViewProjectionMatrix;
+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;
+}
+
+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, 0, 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x - size, sp0.y - size) / Viewport, 0, 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(1, 1);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x + size, sp0.y + size) / Viewport, 0, 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(1, 0);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x + size, sp0.y - size) / Viewport, 0, 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
new file mode 100644
index 00000000000..77fdf58bea0
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
@@ -0,0 +1,15 @@
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in vec4 color;
+in float size;
+
+out vec4 finalColor;
+out float finalThickness;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 );
+ finalColor = color;
+ finalThickness = size;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
new file mode 100644
index 00000000000..35f47d6c418
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
@@ -0,0 +1,140 @@
+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 sampler2D myTexture;
+uniform int texture_clamp;
+
+/* keep this list synchronized with list in gpencil_draw_utils.c */
+#define SOLID 0
+#define GRADIENT 1
+#define RADIAL 2
+#define CHESS 3
+#define TEXTURE 4
+#define PATTERN 5
+
+#define GP_XRAY_FRONT 0
+#define GP_XRAY_3DSPACE 1
+#define GP_XRAY_BACK 2
+
+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);
+ }
+ }
+}
+
+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) ? texture2D(myTexture, rot_tex * texture_scale) : texture2D(myTexture, 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 chesscolor;
+
+ /* 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);
+ }
+ /* chessboard */
+ if (fill_type == CHESS) {
+ 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)) {
+ chesscolor = (texture_flip == 0) ? finalColor : color2;
+ }
+ else {
+ chesscolor = (texture_flip == 0) ? color2 : finalColor;
+ }
+ /* mix with texture */
+ fragColor = (texture_mix == 1) ? mix(chesscolor, text_color, mix_factor) : chesscolor;
+ }
+ /* texture */
+ if (fill_type == TEXTURE) {
+ fragColor = (texture_mix == 1) ? mix(text_color, finalColor, mix_factor) : text_color;
+ }
+ /* pattern */
+ if (fill_type == PATTERN) {
+ fragColor = finalColor;
+ fragColor.a = min(text_color.a, finalColor.a);
+ }
+ }
+
+ /* set zdepth */
+ if (xraymode == GP_XRAY_FRONT) {
+ gl_FragDepth = 0.0;
+ }
+ if (xraymode == GP_XRAY_3DSPACE) {
+ gl_FragDepth = gl_FragCoord.z;
+ }
+ if (xraymode == GP_XRAY_BACK) {
+ gl_FragDepth = 0.999999;
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
new file mode 100644
index 00000000000..52da354a562
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
@@ -0,0 +1,14 @@
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in vec4 color;
+in vec2 texCoord;
+out vec4 finalColor;
+out vec2 texCoord_interp;
+
+void main(void)
+{
+ gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 );
+ finalColor = color;
+ texCoord_interp = texCoord;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl
new file mode 100644
index 00000000000..c2e3f787bec
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl
@@ -0,0 +1,9 @@
+uniform vec3 color;
+uniform float opacity;
+
+out vec4 FragColor;
+
+void main()
+{
+ FragColor = vec4(color, 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
new file mode 100644
index 00000000000..0d6d2b22a55
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
@@ -0,0 +1,49 @@
+uniform int color_type;
+uniform int mode;
+uniform sampler2D myTexture;
+
+in vec4 mColor;
+in vec2 mTexCoord;
+out vec4 fragColor;
+
+#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
+
+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 ((mode != GPENCIL_MODE_BOX) && (dist_squared > rad_squared))
+ discard;
+
+ vec4 tmp_color = texture2D(myTexture, mTexCoord);
+
+ /* Solid */
+ if (color_type == GPENCIL_COLOR_SOLID) {
+ fragColor = mColor;
+ }
+ /* texture */
+ if (color_type == GPENCIL_COLOR_TEXTURE) {
+ fragColor = texture2D(myTexture, mTexCoord);
+ /* 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) {
+ vec4 text_color = texture2D(myTexture, 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);
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl
new file mode 100644
index 00000000000..f092149430c
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl
@@ -0,0 +1,82 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 Viewport;
+uniform int xraymode;
+
+layout(points) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+in vec4 finalColor[1];
+in float finalThickness[1];
+in vec2 finaluvdata[1];
+
+out vec4 mColor;
+out vec2 mTexCoord;
+
+#define GP_XRAY_FRONT 0
+#define GP_XRAY_3DSPACE 1
+#define GP_XRAY_BACK 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 0.0;
+ }
+ if (xraymode == GP_XRAY_3DSPACE) {
+ return (point.z / point.w);
+ }
+ if (xraymode == GP_XRAY_BACK) {
+ return 0.999999;
+ }
+
+ /* in front by default */
+ return 0.0;
+}
+
+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);
+}
+
+void main(void)
+{
+ /* receive 4 points */
+ vec4 P0 = gl_in[0].gl_Position;
+ vec2 sp0 = toScreenSpace(P0);
+
+ float size = finalThickness[0];
+ float aspect = 1.0;
+ /* generate the triangle strip */
+ mTexCoord = rotateUV(vec2(0, 1), finaluvdata[0].y);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x - size, sp0.y + size * aspect) / Viewport, getZdepth(P0), 1.0);
+ EmitVertex();
+
+ mTexCoord = rotateUV(vec2(0, 0), finaluvdata[0].y);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x - size, sp0.y - size * aspect) / Viewport, getZdepth(P0), 1.0);
+ EmitVertex();
+
+ mTexCoord = rotateUV(vec2(1, 1), finaluvdata[0].y);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x + size, sp0.y + size * aspect) / Viewport, getZdepth(P0), 1.0);
+ EmitVertex();
+
+ mTexCoord = rotateUV(vec2(1, 0), finaluvdata[0].y);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x + size, sp0.y - size * aspect) / 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
new file mode 100644
index 00000000000..5e89bf8e5ce
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
@@ -0,0 +1,37 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ProjectionMatrix;
+
+uniform float pixsize; /* rv3d->pixsize */
+uniform float pixelsize; /* U.pixelsize */
+uniform int keep_size;
+uniform float objscale;
+uniform float pixfactor;
+
+in vec3 pos;
+in vec4 color;
+in float thickness;
+in vec2 uvdata;
+
+out vec4 finalColor;
+out float finalThickness;
+out vec2 finaluvdata;
+
+#define TRUE 1
+
+float defaultpixsize = pixsize * pixelsize * (1000.0 / pixfactor);
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 );
+ 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, 4.0); /* minimum 4 pixels */
+ }
+
+ 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
new file mode 100644
index 00000000000..dd54e38c3d0
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl
@@ -0,0 +1,15 @@
+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
new file mode 100644
index 00000000000..d57921c1629
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
@@ -0,0 +1,46 @@
+uniform int color_type;
+uniform sampler2D myTexture;
+
+in vec4 mColor;
+in vec2 mTexCoord;
+in float 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
+
+void main()
+{
+ vec4 tColor = vec4(mColor);
+ /* if alpha < 0, then encap (only solid mode ) */
+ if ((mColor.a < 0) && (color_type == GPENCIL_COLOR_SOLID)) {
+ vec2 center = vec2(uvfac, 1.0);
+ tColor.a = tColor.a * -1.0;
+ float dist = length(mTexCoord - center);
+ if (dist > 0.50) {
+ discard;
+ }
+ }
+ /* Solid */
+ if (color_type == GPENCIL_COLOR_SOLID) {
+ fragColor = tColor;
+ }
+ /* texture */
+ if (color_type == GPENCIL_COLOR_TEXTURE) {
+ fragColor = texture2D(myTexture, mTexCoord);
+ /* mult both alpha factor to use strength factor */
+ fragColor.a = min(fragColor.a * tColor.a, fragColor.a);
+ }
+ /* pattern */
+ if (color_type == GPENCIL_COLOR_PATTERN) {
+ vec4 text_color = texture2D(myTexture, mTexCoord);
+ fragColor = tColor;
+ /* mult both alpha factor to use strength factor with color alpha limit */
+ fragColor.a = min(text_color.a * tColor.a, tColor.a);
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl
new file mode 100644
index 00000000000..0bcfe8cddb7
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl
@@ -0,0 +1,208 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 Viewport;
+uniform int xraymode;
+uniform int color_type;
+
+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 float uvfac;
+
+#define GP_XRAY_FRONT 0
+#define GP_XRAY_3DSPACE 1
+#define GP_XRAY_BACK 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
+
+/* 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 0.0;
+ }
+ if (xraymode == GP_XRAY_3DSPACE) {
+ return (point.z / point.w);
+ }
+ if (xraymode == GP_XRAY_BACK) {
+ return 0.999999;
+ }
+
+ /* in front by default */
+ return 0.0;
+}
+void main(void)
+{
+ float MiterLimit = 0.75;
+ uvfac = 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;
+
+ /* 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 (alpha < 0 used as endcap flag)*/
+ if ((P0 == P2) && (color_type == GPENCIL_COLOR_SOLID)){
+ mTexCoord = vec2(2, 1);
+ mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ;
+ vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0;
+ gl_Position = vec4((sp1 + svn1) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0);
+ mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ;
+ gl_Position = vec4((sp1 - (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 2);
+ mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ;
+ gl_Position = vec4((sp1 + (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+ }
+
+ /* generate the triangle strip */
+ mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(0, 0) : vec2(finaluvdata[1].x, 0);
+ 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, 1);
+ 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, 0);
+ 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, 1);
+ mColor = finalColor[2];
+ gl_Position = vec4((sp2 - length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ /* generate the end endcap (alpha < 0 used as endcap flag)*/
+ if ((P1 == P3) && (color_type == GPENCIL_COLOR_SOLID)){
+ mTexCoord = vec2(finaluvdata[2].x, 2);
+ mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ;
+ uvfac = finaluvdata[2].x;
+ gl_Position = vec4((sp2 + (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(finaluvdata[2].x, 0);
+ mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ;
+ uvfac = finaluvdata[2].x;
+ gl_Position = vec4((sp2 - (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(finaluvdata[2].x + 2, 1);
+ mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ;
+ uvfac = finaluvdata[2].x;
+ 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
new file mode 100644
index 00000000000..2f9a105e911
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
@@ -0,0 +1,37 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ProjectionMatrix;
+
+uniform float pixsize; /* rv3d->pixsize */
+uniform float pixelsize; /* U.pixelsize */
+uniform int keep_size;
+uniform float objscale;
+uniform float pixfactor;
+
+in vec3 pos;
+in vec4 color;
+in float thickness;
+in vec2 uvdata;
+
+out vec4 finalColor;
+out float finalThickness;
+out vec2 finaluvdata;
+
+#define TRUE 1
+
+float defaultpixsize = pixsize * pixelsize * (1000.0 / pixfactor);
+
+void main(void)
+{
+ gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 );
+ 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);
+ }
+
+ finaluvdata = uvdata;
+}
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
new file mode 100644
index 00000000000..0983e6c4d87
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl
@@ -0,0 +1,45 @@
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+uniform int tonemapping;
+
+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;
+}
+
+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 = stroke_color;
+ gl_FragDepth = stroke_depth;
+}
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 0db16ab5472..abba8d3ce91 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -136,6 +136,7 @@ typedef char DRWViewportEmptyList;
+
typedef struct DrawEngineDataSize {
int fbl_len;
int txl_len;
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index bdfa3211f7c..ac84a847a1b 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -107,6 +107,7 @@ static struct DRWShapeCache {
GPUBatch *drw_particle_cross;
GPUBatch *drw_particle_circle;
GPUBatch *drw_particle_axis;
+ GPUBatch *drw_gpencil_axes;
} SHC = {NULL};
void DRW_shape_cache_free(void)
@@ -551,12 +552,67 @@ GPUBatch *DRW_cache_screenspace_circle_get(void)
#undef CIRCLE_RESOL
}
-/** \} */
+/* Grease Pencil object */
+GPUBatch *DRW_cache_gpencil_axes_get(void)
+{
+ if (!SHC.drw_gpencil_axes) {
+ int axis;
+ float v1[3] = { 0.0f, 0.0f, 0.0f };
+ float v2[3] = { 0.0f, 0.0f, 0.0f };
+
+ /* cube data */
+ const GLfloat verts[8][3] = {
+ { -0.25f, -0.25f, -0.25f },
+ { -0.25f, -0.25f, 0.25f },
+ { -0.25f, 0.25f, -0.25f },
+ { -0.25f, 0.25f, 0.25f },
+ { 0.25f, -0.25f, -0.25f },
+ { 0.25f, -0.25f, 0.25f },
+ { 0.25f, 0.25f, -0.25f },
+ { 0.25f, 0.25f, 0.25f }
+ };
+
+ const GLubyte indices[24] = { 0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6 };
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static uint pos_id;
+ if (format.attr_len == 0) {
+ pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+
+ /* alloc 30 elements for cube and 3 axis */
+ GPU_vertbuf_data_alloc(vbo, ARRAY_SIZE(indices) + 6);
+
+ /* draw axis */
+ for (axis = 0; axis < 3; axis++) {
+ v1[axis] = 1.0f;
+ v2[axis] = -1.0f;
+
+ GPU_vertbuf_attr_set(vbo, pos_id, axis * 2, v1);
+ GPU_vertbuf_attr_set(vbo, pos_id, axis * 2 + 1, v2);
+
+ /* reset v1 & v2 to zero for next axis */
+ v1[axis] = v2[axis] = 0.0f;
+ }
+
+ /* draw cube */
+ for (int i = 0; i < 24; ++i) {
+ GPU_vertbuf_attr_set(vbo, pos_id, i + 6, verts[indices[i]]);
+ }
+
+ SHC.drw_gpencil_axes = GPU_batch_create(GPU_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_gpencil_axes;
+}
+
/* -------------------------------------------------------------------- */
/** \name Common Object API
- * \{ */
+* \{ */
GPUBatch *DRW_cache_object_wire_outline_get(Object *ob)
{
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 129c0252f30..7d0996b3059 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -82,6 +82,9 @@ struct GPUBatch *DRW_cache_field_vortex_get(void);
struct GPUBatch *DRW_cache_field_tube_limit_get(void);
struct GPUBatch *DRW_cache_field_cone_limit_get(void);
+/* Grease Pencil */
+struct GPUBatch *DRW_cache_gpencil_axes_get(void);
+
/* Lamps */
struct GPUBatch *DRW_cache_lamp_get(void);
struct GPUBatch *DRW_cache_lamp_shadows_get(void);
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index eeb7b1c41ee..d4dbe5db80d 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -41,6 +41,7 @@ struct Curve;
struct Lattice;
struct Mesh;
struct MetaBall;
+struct bGPdata;
/* Expose via BKE callbacks */
void DRW_mball_batch_cache_dirty(struct MetaBall *mb, int mode);
@@ -58,6 +59,9 @@ void DRW_lattice_batch_cache_free(struct Lattice *lt);
void DRW_particle_batch_cache_dirty(struct ParticleSystem *psys, int mode);
void DRW_particle_batch_cache_free(struct ParticleSystem *psys);
+void DRW_gpencil_batch_cache_dirty(struct bGPdata *gpd);
+void DRW_gpencil_batch_cache_free(struct bGPdata *gpd);
+
/* Curve */
struct GPUBatch *DRW_curve_batch_cache_get_wire_edge(struct Curve *cu, struct CurveCache *ob_curve_cache);
struct GPUBatch *DRW_curve_batch_cache_get_normal_edge(
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 714edc23719..e6e20934283 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -48,6 +48,7 @@
#include "ED_space_api.h"
#include "ED_screen.h"
+#include "ED_gpencil.h"
#include "ED_particle.h"
#include "ED_view3d.h"
@@ -1222,10 +1223,17 @@ static void drw_engines_enable_from_mode(int mode)
break;
case CTX_MODE_OBJECT:
break;
+ case CTX_MODE_GPENCIL_PAINT:
+ case CTX_MODE_GPENCIL_EDIT:
+ case CTX_MODE_GPENCIL_SCULPT:
+ case CTX_MODE_GPENCIL_WEIGHT:
+ break;
default:
BLI_assert(!"Draw mode invalid");
break;
}
+ /* grease pencil */
+ use_drw_engine(&draw_engine_gpencil_type);
}
static void drw_engines_enable_from_overlays(int overlay_flag)
@@ -1258,6 +1266,10 @@ static void drw_engines_enable(ViewLayer *view_layer, RenderEngineType *engine_t
drw_engines_enable_from_object_mode();
drw_engines_enable_from_mode(mode);
}
+ else {
+ /* if gpencil must draw the strokes, but not the object */
+ drw_engines_enable_from_mode(mode);
+ }
}
static void drw_engines_disable(void)
@@ -1377,6 +1389,7 @@ void DRW_draw_render_loop_ex(
Scene *scene = DEG_get_evaluated_scene(depsgraph);
ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
RegionView3D *rv3d = ar->regiondata;
+ bool do_annotations = (((v3d->flag2 & V3D_SHOW_ANNOTATION) != 0) && ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0));
DST.draw_ctx.evil_C = evil_C;
DST.viewport = viewport;
@@ -1471,6 +1484,17 @@ void DRW_draw_render_loop_ex(
drw_engines_draw_scene();
+ /* annotations - temporary drawing buffer (3d space) */
+ /* XXX: Or should we use a proper draw/overlay engine for this case? */
+ if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (do_annotations))
+ {
+ glDisable(GL_DEPTH_TEST);
+ /* XXX: as scene->gpd is not copied for COW yet */
+ ED_gpencil_draw_view3d_annotations(DEG_get_input_scene(depsgraph), depsgraph, v3d, ar, true);
+ glEnable(GL_DEPTH_TEST);
+ }
+
DRW_draw_callbacks_post_scene();
if (DST.draw_ctx.evil_C) {
ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.ar, REGION_DRAW_POST_VIEW);
@@ -1495,6 +1519,17 @@ void DRW_draw_render_loop_ex(
DRW_draw_region_info();
+ /* annotations - temporary drawing buffer (screenspace) */
+ /* XXX: Or should we use a proper draw/overlay engine for this case? */
+ if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (do_annotations))
+ {
+ glDisable(GL_DEPTH_TEST);
+ /* XXX: as scene->gpd is not copied for COW yet */
+ ED_gpencil_draw_view3d_annotations(DEG_get_input_scene(depsgraph), depsgraph, v3d, ar, false);
+ glEnable(GL_DEPTH_TEST);
+ }
+
if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
/* Draw 2D after region info so we can draw on top of the camera passepartout overlay.
* 'DRW_draw_region_info' sets the projection in pixel-space. */
@@ -1583,6 +1618,105 @@ void DRW_draw_render_loop_offscreen(
GPU_offscreen_bind(ofs, false);
}
+/* helper to check if exit object type to render */
+static bool DRW_render_check_object_type(struct Depsgraph *depsgraph, short obtype)
+{
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob)
+ {
+ if ((ob->type == obtype) && (DRW_check_object_visible_within_active_context(ob))) {
+ return true;
+ }
+ }
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END
+
+ return false;
+}
+
+static void DRW_render_gpencil_to_image(RenderEngine *engine, struct Depsgraph *depsgraph, struct RenderLayer *render_layer, const rcti *rect)
+{
+ if (draw_engine_gpencil_type.render_to_image) {
+ if (DRW_render_check_object_type(depsgraph, OB_GPENCIL)) {
+ ViewportEngineData *gpdata = drw_viewport_engine_data_ensure(&draw_engine_gpencil_type);
+ draw_engine_gpencil_type.render_to_image(gpdata, engine, render_layer, rect);
+ }
+ }
+}
+
+void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph)
+{
+ /* This function is only valid for Cycles
+ * Eevee done all work in the Eevee render directly.
+ * Maybe it can be done equal for both engines?
+ */
+ if (STREQ(engine->type->name, "Eevee")) {
+ return;
+ }
+
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ RenderEngineType *engine_type = engine->type;
+ RenderData *r = &scene->r;
+ Render *render = engine->re;
+ /* Changing Context */
+ /* GPXX Review this context */
+ DRW_opengl_context_enable();
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+ DST.options.is_image_render = true;
+ DST.options.is_scene_render = true;
+ DST.options.draw_background = scene->r.alphamode == R_ADDSKY;
+ DST.buffer_finish_called = true;
+
+ DST.draw_ctx = (DRWContextState) {
+ .scene = scene, .view_layer = view_layer,
+ .engine_type = engine_type,
+ .depsgraph = depsgraph, .object_mode = OB_MODE_OBJECT,
+ };
+ drw_context_state_init();
+
+ DST.viewport = GPU_viewport_create();
+ const int size[2] = { (r->size * r->xsch) / 100, (r->size * r->ysch) / 100 };
+ GPU_viewport_size_set(DST.viewport, size);
+
+ drw_viewport_var_init();
+
+ /* set default viewport */
+ gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT);
+ glDisable(GL_SCISSOR_TEST);
+ glViewport(0, 0, size[0], size[1]);
+
+ /* Main rendering. */
+ rctf view_rect;
+ rcti render_rect;
+ RE_GetViewPlane(render, &view_rect, &render_rect);
+ if (BLI_rcti_is_empty(&render_rect)) {
+ BLI_rcti_init(&render_rect, 0, size[0], 0, size[1]);
+ }
+
+ RenderResult *render_result = RE_engine_get_result(engine);
+ RenderLayer *render_layer = render_result->layers.first;
+
+ DRW_render_gpencil_to_image(engine, depsgraph, render_layer, &render_rect);
+
+ /* Force cache to reset. */
+ drw_viewport_cache_resize();
+ GPU_viewport_free(DST.viewport);
+ DRW_state_reset();
+
+ glDisable(GL_DEPTH_TEST);
+
+ /* Restore Drawing area. */
+ gpuPopAttrib();
+ glEnable(GL_SCISSOR_TEST);
+ GPU_framebuffer_restore();
+
+ /* Changing Context */
+ /* GPXX Review this context */
+ DRW_opengl_context_disable();
+
+ DST.buffer_finish_called = false;
+}
+
void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
@@ -1663,6 +1797,8 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
{
RE_SetActiveRenderView(render, render_view->name);
engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect);
+ /* grease pencil: render result is merged in the previous render result. */
+ DRW_render_gpencil_to_image(engine, depsgraph, render_layer, &render_rect);
DST.buffer_finish_called = false;
}
@@ -1671,8 +1807,6 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
/* Force cache to reset. */
drw_viewport_cache_resize();
- /* TODO grease pencil */
-
GPU_viewport_free(DST.viewport);
GPU_framebuffer_restore();
@@ -2286,6 +2420,7 @@ void DRW_engines_register(void)
DRW_engine_register(&draw_engine_particle_type);
DRW_engine_register(&draw_engine_pose_type);
DRW_engine_register(&draw_engine_sculpt_type);
+ DRW_engine_register(&draw_engine_gpencil_type);
/* setup callbacks */
{
@@ -2304,6 +2439,9 @@ void DRW_engines_register(void)
/* BKE: particle.c */
extern void *BKE_particle_batch_cache_dirty_cb;
extern void *BKE_particle_batch_cache_free_cb;
+ /* BKE: gpencil.c */
+ extern void *BKE_gpencil_batch_cache_dirty_cb;
+ extern void *BKE_gpencil_batch_cache_free_cb;
BKE_mball_batch_cache_dirty_cb = DRW_mball_batch_cache_dirty;
BKE_mball_batch_cache_free_cb = DRW_mball_batch_cache_free;
@@ -2319,6 +2457,9 @@ void DRW_engines_register(void)
BKE_particle_batch_cache_dirty_cb = DRW_particle_batch_cache_dirty;
BKE_particle_batch_cache_free_cb = DRW_particle_batch_cache_free;
+
+ BKE_gpencil_batch_cache_dirty_cb = DRW_gpencil_batch_cache_dirty;
+ BKE_gpencil_batch_cache_free_cb = DRW_gpencil_batch_cache_free;
}
}
diff --git a/source/blender/draw/modes/draw_mode_engines.h b/source/blender/draw/modes/draw_mode_engines.h
index f88d49dfa96..8e8ddfef5a4 100644
--- a/source/blender/draw/modes/draw_mode_engines.h
+++ b/source/blender/draw/modes/draw_mode_engines.h
@@ -42,5 +42,6 @@ extern DrawEngineType draw_engine_particle_type;
extern DrawEngineType draw_engine_pose_type;
extern DrawEngineType draw_engine_sculpt_type;
extern DrawEngineType draw_engine_overlay_type;
+extern DrawEngineType draw_engine_gpencil_type;
#endif /* __DRAW_MODE_ENGINES_H__ */
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index db906714dd5..675a2a02db8 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -165,6 +165,9 @@ typedef struct OBJECT_PrivateData {
DRWShadingGroup *field_tube_limit;
DRWShadingGroup *field_cone_limit;
+ /* Grease Pencil */
+ DRWShadingGroup *gpencil_axes;
+
/* Speaker */
DRWShadingGroup *speaker;
@@ -1136,6 +1139,10 @@ static void OBJECT_cache_init(void *vedata)
geom = DRW_cache_screenspace_circle_get();
stl->g_data->field_curve_sta = shgroup_instance_screen_aligned(psl->non_meshes, geom);
+ /* Grease Pencil */
+ geom = DRW_cache_gpencil_axes_get();
+ stl->g_data->gpencil_axes = shgroup_instance(psl->non_meshes, geom);
+
/* Speaker */
geom = DRW_cache_speaker_get();
stl->g_data->speaker = shgroup_instance(psl->non_meshes, geom);
@@ -1820,6 +1827,14 @@ static void volumes_free_smoke_textures(void)
BLI_freelistN(&e_data.smoke_domains);
}
+static void DRW_shgroup_gpencil(OBJECT_StorageList *stl, Object *ob, ViewLayer *view_layer)
+{
+ float *color;
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->gpencil_axes, color, &ob->empty_drawsize, ob->obmat);
+}
+
static void DRW_shgroup_speaker(OBJECT_StorageList *stl, Object *ob, ViewLayer *view_layer)
{
float *color;
@@ -2445,6 +2460,9 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
}
DRW_shgroup_empty(stl, psl, ob, view_layer);
break;
+ case OB_GPENCIL:
+ DRW_shgroup_gpencil(stl, ob, view_layer);
+ break;
case OB_SPEAKER:
if (hide_object_extra) {
break;
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 3c10cda6456..2431bd50e1b 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -64,6 +64,7 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
+#include "BKE_gpencil.h"
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_nla.h"
@@ -83,6 +84,8 @@
#include "BIF_gl.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -661,6 +664,8 @@ static int acf_object_icon(bAnimListElem *ale)
return ICON_OUTLINER_OB_SURFACE;
case OB_EMPTY:
return ICON_OUTLINER_OB_EMPTY;
+ case OB_GPENCIL:
+ return ICON_OUTLINER_OB_GREASEPENCIL;
default:
return ICON_OBJECT_DATA;
}
@@ -4048,8 +4053,16 @@ static void achannel_setting_flush_widget_cb(bContext *C, void *ale_npoin, void
return;
}
- if (ale_setting->type == ANIMTYPE_GPLAYER)
+ if (ale_setting->type == ANIMTYPE_GPLAYER) {
+ /* draw cache updates for settings that affect the visible strokes */
+ if (setting == ACHANNEL_SETTING_VISIBLE) {
+ bGPdata *gpd = (bGPdata *)ale_setting->id;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ }
+
+ /* UI updates */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ }
/* tag copy-on-write flushing (so that the settings will have an effect) */
if (ale_setting->id) {
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index d768be49ad4..3f22ac6fa3a 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -1727,8 +1727,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
bGPDlayer *gpl = (bGPDlayer *)ale->data;
/* try to delete the layer's data and the layer itself */
- BKE_gpencil_free_frames(gpl);
- BLI_freelinkN(&gpd->layers, gpl);
+ BKE_gpencil_layer_delete(gpd, gpl);
break;
}
case ANIMTYPE_MASKLAYER:
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index adb5a10c19d..898c8b6464a 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -435,6 +435,16 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
ANIM_list_elem_update(ac->bmain, ac->scene, ale);
}
}
+ else if (ale->update) {
+#if 0
+ if (G.debug & G_DEBUG) {
+ printf("%s: Unhandled animchannel updates (%d) for type=%d (%p)\n",
+ __func__, ale->update, ale->type, ale->data);
+ }
+#endif
+ /* Prevent crashes in cases where it can't be handled */
+ ale->update = 0;
+ }
BLI_assert(ale->update == 0);
}
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 780e984f870..05ea3fd6314 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -552,11 +552,11 @@ static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prev
/* populate tree with keyframe nodes */
scene_to_keylist(&ads, scene, &keys, NULL);
- gpencil_to_keylist(&ads, scene->gpd, &keys);
+ gpencil_to_keylist(&ads, scene->gpd, &keys, false);
if (ob) {
ob_to_keylist(&ads, ob, &keys, NULL);
- gpencil_to_keylist(&ads, ob->gpd, &keys);
+ gpencil_to_keylist(&ads, ob->data, &keys, false);
}
if (mask) {
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index c59d24bbdf8..1981814eb02 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -72,6 +72,7 @@
#include "DNA_speaker_types.h"
#include "DNA_world_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "DNA_userdef_types.h"
#include "DNA_layer_types.h"
@@ -1660,7 +1661,7 @@ static size_t animdata_filter_gpencil_data(ListBase *anim_data, bDopeSheet *ads,
*/
if (filter_mode & ANIMFILTER_ANIMDATA) {
/* just add GPD as a channel - this will add everything needed */
- ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
+ ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, gpd);
}
else {
ListBase tmp_data = {NULL, NULL};
@@ -1711,7 +1712,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi
/* Objects in the scene */
for (base = view_layer->object_bases.first; base; base = base->next) {
/* Only consider this object if it has got some GP data (saving on all the other tests) */
- if (base->object && base->object->gpd) {
+ if (base->object && (base->object->type == OB_GPENCIL)) {
Object *ob = base->object;
/* firstly, check if object can be included, by the following factors:
@@ -1748,7 +1749,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi
/* finally, include this object's grease pencil datablock */
/* XXX: Should we store these under expanders per item? */
- items += animdata_filter_gpencil_data(anim_data, ads, ob->gpd, filter_mode);
+ items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode);
}
}
}
@@ -2613,8 +2614,10 @@ static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data
}
/* grease pencil */
- if ((ob->gpd) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) {
- tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->gpd, filter_mode);
+ if ((ob->type == OB_GPENCIL) &&
+ (ob->data) && !(ads->filterflag & ADS_FILTER_NOGPENCIL))
+ {
+ tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->data, filter_mode);
}
}
END_ANIMFILTER_SUBCHANNELS;
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 30130ce4dac..a8b63e01ac1 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -48,6 +48,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_brush_types.h"
#include "DNA_mask_types.h"
#include "BKE_fcurve.h"
@@ -783,7 +784,7 @@ void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos
BLI_dlrbTree_init(&keys);
- gpencil_to_keylist(ads, gpd, &keys);
+ gpencil_to_keylist(ads, gpd, &keys, false);
BLI_dlrbTree_linkedlist_sync(&keys);
@@ -1019,7 +1020,7 @@ void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, DLRBT_Tree
}
-void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys)
+void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys, const bool active)
{
bGPDlayer *gpl;
@@ -1027,7 +1028,9 @@ void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys)
/* for now, just aggregate out all the frames, but only for visible layers */
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
if ((gpl->flag & GP_LAYER_HIDE) == 0) {
- gpl_to_keylist(ads, gpl, keys);
+ if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) {
+ gpl_to_keylist(ads, gpl, keys);
+ }
}
}
}
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 0e09ef6f583..0698282c4e5 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -536,6 +536,16 @@ set(ICON_NAMES
# This section is maintained by the updating script, keep BEGIN/END comments.
set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
# BEGIN ICON_GEOM_NAMES
+ brush.gpencil.draw.eraser_hard
+ brush.gpencil.draw.eraser_soft
+ brush.gpencil.draw.eraser_stroke
+ brush.gpencil.draw_block
+ brush.gpencil.draw_fill
+ brush.gpencil.draw_ink
+ brush.gpencil.draw_marker
+ brush.gpencil.draw_noise
+ brush.gpencil.draw_pen
+ brush.gpencil.draw_pencil
brush.paint_texture.airbrush
brush.paint_texture.clone
brush.paint_texture.draw
@@ -583,6 +593,24 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.generic.select_border
ops.generic.select_circle
ops.generic.select_lasso
+ ops.gpencil.draw
+ ops.gpencil.draw.eraser
+ ops.gpencil.draw.line
+ ops.gpencil.draw.poly
+ ops.gpencil.edit_bend
+ ops.gpencil.edit_mirror
+ ops.gpencil.edit_shear
+ ops.gpencil.edit_to_sphere
+ ops.gpencil.sculpt_clone
+ ops.gpencil.sculpt_grab
+ ops.gpencil.sculpt_pinch
+ ops.gpencil.sculpt_push
+ ops.gpencil.sculpt_randomize
+ ops.gpencil.sculpt_smooth
+ ops.gpencil.sculpt_strength
+ ops.gpencil.sculpt_thickness
+ ops.gpencil.sculpt_twist
+ ops.gpencil.sculpt_weight
ops.mesh.bevel
ops.mesh.bisect
ops.mesh.dupli_extrude_cursor
@@ -634,6 +662,7 @@ if(WITH_BLENDER)
# blends
data_to_c_simple(../../../../release/datafiles/preview.blend SRC)
data_to_c_simple(../../../../release/datafiles/preview_cycles.blend SRC)
+ data_to_c_simple(../../../../release/datafiles/preview_grease_pencil.blend SRC)
# images
data_to_c_simple(../../../../release/datafiles/splash.png SRC)
@@ -689,6 +718,29 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/brushicons/twist.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/vertexdraw.png SRC)
+ # grease pencil sculpt
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_smooth.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_thickness.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_strength.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_grab.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_push.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_twist.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_pinch.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_randomize.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_clone.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_weight.png SRC)
+
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_pencil.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_pen.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_ink.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_inknoise.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_block.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_marker.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_fill.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_soft.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_hard.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_stroke.png SRC)
+
endif()
data_to_c_simple(../../../../release/datafiles/startup.blend SRC)
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 587c25031ab..f9f196f6634 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -39,18 +39,24 @@ set(INC_SYS
)
set(SRC
+ annotate_draw.c
+ annotate_paint.c
drawgpencil.c
editaction_gpencil.c
+ gpencil_add_monkey.c
gpencil_brush.c
gpencil_convert.c
gpencil_data.c
gpencil_edit.c
gpencil_interpolate.c
+ gpencil_primitive.c
gpencil_ops.c
gpencil_paint.c
+ gpencil_fill.c
gpencil_select.c
gpencil_undo.c
gpencil_utils.c
+ gpencil_old.c
gpencil_intern.h
)
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
new file mode 100644
index 00000000000..dad5af7379c
--- /dev/null
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -0,0 +1,1065 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Joshua Leung, Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/gpencil/annotate_draw.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_sys_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_polyfill_2d.h"
+
+#include "BLF_api.h"
+#include "BLT_translation.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+
+#include "WM_api.h"
+
+#include "BIF_glutil.h"
+
+#include "GPU_immediate.h"
+#include "GPU_draw.h"
+#include "GPU_state.h"
+
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_space_api.h"
+
+#include "UI_interface_icons.h"
+#include "UI_resources.h"
+
+/* ************************************************** */
+/* GREASE PENCIL DRAWING */
+
+/* ----- General Defines ------ */
+/* flags for sflag */
+typedef enum eDrawStrokeFlags {
+ GP_DRAWDATA_NOSTATUS = (1 << 0), /* don't draw status info */
+ GP_DRAWDATA_ONLY3D = (1 << 1), /* only draw 3d-strokes */
+ GP_DRAWDATA_ONLYV2D = (1 << 2), /* only draw 'canvas' strokes */
+ GP_DRAWDATA_ONLYI2D = (1 << 3), /* only draw 'image' strokes */
+ GP_DRAWDATA_IEDITHACK = (1 << 4), /* special hack for drawing strokes in Image Editor (weird coordinates) */
+ GP_DRAWDATA_NO_XRAY = (1 << 5), /* don't draw xray in 3D view (which is default) */
+ GP_DRAWDATA_NO_ONIONS = (1 << 6), /* no onionskins should be drawn (for animation playback) */
+} eDrawStrokeFlags;
+
+
+/* ----- Tool Buffer Drawing ------ */
+
+/* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
+static void gp_draw_stroke_buffer(const tGPspoint *points, int totpoints, short thickness,
+ short dflag, short sflag, float ink[4])
+{
+ int draw_points = 0;
+
+ /* error checking */
+ if ((points == NULL) || (totpoints <= 0))
+ return;
+
+ /* check if buffer can be drawn */
+ if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D))
+ return;
+
+ if (sflag & GP_STROKE_ERASER) {
+ /* don't draw stroke at all! */
+ return;
+ }
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+
+ const tGPspoint *pt = points;
+
+ if (totpoints == 1) {
+ /* if drawing a single point, draw it larger */
+ GPU_point_size((float)(thickness + 2) * points->pressure);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ immUniformColor3fvAlpha(ink, ink[3]);
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex2iv(pos, &pt->x);
+ }
+ else {
+ float oldpressure = points[0].pressure;
+
+ /* draw stroke curve */
+ GPU_line_width(max_ff(oldpressure * thickness, 1.0));
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(ink, ink[3]);
+
+ /* TODO: implement this with a geometry shader to draw one continuous tapered stroke */
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints);
+
+ for (int i = 0; i < totpoints; i++, pt++) {
+ /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
+ * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
+ */
+ if (fabsf(pt->pressure - oldpressure) > 0.2f) {
+ /* need to have 2 points to avoid immEnd assert error */
+ if (draw_points < 2) {
+ immVertex2iv(pos, &(pt - 1)->x);
+ }
+
+ immEnd();
+ draw_points = 0;
+
+ GPU_line_width(max_ff(pt->pressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1);
+
+ /* need to roll-back one point to ensure that there are no gaps in the stroke */
+ if (i != 0) {
+ immVertex2iv(pos, &(pt - 1)->x);
+ draw_points++;
+ }
+
+ oldpressure = pt->pressure; /* reset our threshold */
+ }
+
+ /* now the point we want */
+ immVertex2iv(pos, &pt->x);
+ draw_points++;
+ }
+ /* need to have 2 points to avoid immEnd assert error */
+ if (draw_points < 2) {
+ immVertex2iv(pos, &(pt - 1)->x);
+ }
+ }
+
+ immEnd();
+ immUnbindProgram();
+}
+
+/* --------- 2D Stroke Drawing Helpers --------- */
+/* change in parameter list */
+static void gp_calc_2d_stroke_fxy(const float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
+{
+ if (sflag & GP_STROKE_2DSPACE) {
+ r_co[0] = pt[0];
+ r_co[1] = pt[1];
+ }
+ else if (sflag & GP_STROKE_2DIMAGE) {
+ const float x = (float)((pt[0] * winx) + offsx);
+ const float y = (float)((pt[1] * winy) + offsy);
+
+ r_co[0] = x;
+ r_co[1] = y;
+ }
+ else {
+ const float x = (float)(pt[0] / 100 * winx) + offsx;
+ const float y = (float)(pt[1] / 100 * winy) + offsy;
+
+ r_co[0] = x;
+ r_co[1] = y;
+ }
+}
+
+/* ----- Existing Strokes Drawing (3D and Point) ------ */
+
+/* draw a given stroke - just a single dot (only one point) */
+static void gp_draw_stroke_point(
+ const bGPDspoint *points, short thickness, short UNUSED(dflag), short sflag,
+ int offsx, int offsy, int winx, int winy, const float ink[4])
+{
+ const bGPDspoint *pt = points;
+
+ /* get final position using parent matrix */
+ float fpt[3];
+ copy_v3_v3(fpt, &pt->x);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ if (sflag & GP_STROKE_3DSPACE) {
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+
+ /* get 2D coordinates of point */
+ float co[3] = { 0.0f };
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
+ copy_v3_v3(fpt, co);
+ }
+
+ /* set color */
+ immUniformColor3fvAlpha(ink, ink[3]);
+
+ /* set point thickness (since there's only one of these) */
+ immUniform1f("size", (float)(thickness + 2) * pt->pressure);
+
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(pos, fpt);
+ immEnd();
+
+ immUnbindProgram();
+}
+
+/* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
+static void gp_draw_stroke_3d(const bGPDspoint *points, int totpoints, short thickness, bool UNUSED(debug),
+ short UNUSED(sflag), const float ink[4], bool cyclic)
+{
+ float curpressure = points[0].pressure;
+ float cyclic_fpt[3];
+ int draw_points = 0;
+
+ /* if cyclic needs one vertex more */
+ int cyclic_add = 0;
+ if (cyclic) {
+ cyclic_add++;
+ }
+
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(ink, ink[3]);
+
+ /* TODO: implement this with a geometry shader to draw one continuous tapered stroke */
+
+ /* draw stroke curve */
+ GPU_line_width(max_ff(curpressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
+ const bGPDspoint *pt = points;
+ for (int i = 0; i < totpoints; i++, pt++) {
+ /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
+ * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
+ * Note: we want more visible levels of pressures when thickness is bigger.
+ */
+ if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) {
+ /* if the pressure changes before get at least 2 vertices, need to repeat last point to avoid assert in immEnd() */
+ if (draw_points < 2) {
+ const bGPDspoint *pt2 = pt - 1;
+ immVertex3fv(pos, &pt2->x);
+ }
+ immEnd();
+ draw_points = 0;
+
+ curpressure = pt->pressure;
+ GPU_line_width(max_ff(curpressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1 + cyclic_add);
+
+ /* need to roll-back one point to ensure that there are no gaps in the stroke */
+ if (i != 0) {
+ const bGPDspoint *pt2 = pt - 1;
+ immVertex3fv(pos, &pt2->x);
+ draw_points++;
+ }
+ }
+
+ /* now the point we want */
+ immVertex3fv(pos, &pt->x);
+ draw_points++;
+
+ if (cyclic && i == 0) {
+ /* save first point to use in cyclic */
+ copy_v3_v3(cyclic_fpt, &pt->x);
+ }
+ }
+
+ if (cyclic) {
+ /* draw line to first point to complete the cycle */
+ immVertex3fv(pos, cyclic_fpt);
+ draw_points++;
+ }
+
+ /* if less of two points, need to repeat last point to avoid assert in immEnd() */
+ if (draw_points < 2) {
+ const bGPDspoint *pt2 = pt - 1;
+ immVertex3fv(pos, &pt2->x);
+ }
+
+ immEnd();
+ immUnbindProgram();
+}
+
+/* ----- Fancy 2D-Stroke Drawing ------ */
+
+/* draw a given stroke in 2d */
+static void gp_draw_stroke_2d(const bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
+ bool UNUSED(debug), int offsx, int offsy, int winx, int winy, const float ink[4])
+{
+ /* otherwise thickness is twice that of the 3D view */
+ float thickness = (float)thickness_s * 0.5f;
+
+ /* strokes in Image Editor need a scale factor, since units there are not pixels! */
+ float scalefac = 1.0f;
+ if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
+ scalefac = 0.001f;
+ }
+
+ /* TODO: fancy++ with the magic of shaders */
+
+ /* tessellation code - draw stroke as series of connected quads (triangle strips in fact) with connection
+ * edges rotated to minimize shrinking artifacts, and rounded endcaps
+ */
+ {
+ const bGPDspoint *pt1, *pt2;
+ float s0[2], s1[2]; /* segment 'center' points */
+ float pm[2]; /* normal from previous segment. */
+ int i;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(ink, ink[3]);
+ immBegin(GPU_PRIM_TRI_STRIP, totpoints * 2 + 4);
+
+ /* get x and y coordinates from first point */
+ gp_calc_2d_stroke_fxy(&points->x, sflag, offsx, offsy, winx, winy, s0);
+
+ for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
+ float t0[2], t1[2]; /* tessellated coordinates */
+ float m1[2], m2[2]; /* gradient and normal */
+ float mt[2], sc[2]; /* gradient for thickness, point for end-cap */
+ float pthick; /* thickness at segment point */
+
+ /* get x and y coordinates from point2 (point1 has already been computed in previous iteration). */
+ gp_calc_2d_stroke_fxy(&pt2->x, sflag, offsx, offsy, winx, winy, s1);
+
+ /* calculate gradient and normal - 'angle'=(ny/nx) */
+ m1[1] = s1[1] - s0[1];
+ m1[0] = s1[0] - s0[0];
+ normalize_v2(m1);
+ m2[1] = -m1[0];
+ m2[0] = m1[1];
+
+ /* always use pressure from first point here */
+ pthick = (pt1->pressure * thickness * scalefac);
+
+ /* if the first segment, start of segment is segment's normal */
+ if (i == 0) {
+ /* draw start cap first
+ * - make points slightly closer to center (about halfway across)
+ */
+ mt[0] = m2[0] * pthick * 0.5f;
+ mt[1] = m2[1] * pthick * 0.5f;
+ sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
+ sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
+
+ t0[0] = sc[0] - mt[0];
+ t0[1] = sc[1] - mt[1];
+ t1[0] = sc[0] + mt[0];
+ t1[1] = sc[1] + mt[1];
+
+ /* First two points of cap. */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+
+ /* calculate points for start of segment */
+ mt[0] = m2[0] * pthick;
+ mt[1] = m2[1] * pthick;
+
+ t0[0] = s0[0] - mt[0];
+ t0[1] = s0[1] - mt[1];
+ t1[0] = s0[0] + mt[0];
+ t1[1] = s0[1] + mt[1];
+
+ /* Last two points of start cap (and first two points of first segment). */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+ }
+ /* if not the first segment, use bisector of angle between segments */
+ else {
+ float mb[2]; /* bisector normal */
+ float athick, dfac; /* actual thickness, difference between thicknesses */
+
+ /* calculate gradient of bisector (as average of normals) */
+ mb[0] = (pm[0] + m2[0]) / 2;
+ mb[1] = (pm[1] + m2[1]) / 2;
+ normalize_v2(mb);
+
+ /* calculate gradient to apply
+ * - as basis, use just pthick * bisector gradient
+ * - if cross-section not as thick as it should be, add extra padding to fix it
+ */
+ mt[0] = mb[0] * pthick;
+ mt[1] = mb[1] * pthick;
+ athick = len_v2(mt);
+ dfac = pthick - (athick * 2);
+
+ if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
+ mt[0] += (mb[0] * dfac);
+ mt[1] += (mb[1] * dfac);
+ }
+
+ /* calculate points for start of segment */
+ t0[0] = s0[0] - mt[0];
+ t0[1] = s0[1] - mt[1];
+ t1[0] = s0[0] + mt[0];
+ t1[1] = s0[1] + mt[1];
+
+ /* Last two points of previous segment, and first two points of current segment. */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+ }
+
+ /* if last segment, also draw end of segment (defined as segment's normal) */
+ if (i == totpoints - 2) {
+ /* for once, we use second point's pressure (otherwise it won't be drawn) */
+ pthick = (pt2->pressure * thickness * scalefac);
+
+ /* calculate points for end of segment */
+ mt[0] = m2[0] * pthick;
+ mt[1] = m2[1] * pthick;
+
+ t0[0] = s1[0] - mt[0];
+ t0[1] = s1[1] - mt[1];
+ t1[0] = s1[0] + mt[0];
+ t1[1] = s1[1] + mt[1];
+
+ /* Last two points of last segment (and first two points of end cap). */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+
+ /* draw end cap as last step
+ * - make points slightly closer to center (about halfway across)
+ */
+ mt[0] = m2[0] * pthick * 0.5f;
+ mt[1] = m2[1] * pthick * 0.5f;
+ sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
+ sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
+
+ t0[0] = sc[0] - mt[0];
+ t0[1] = sc[1] - mt[1];
+ t1[0] = sc[0] + mt[0];
+ t1[1] = sc[1] + mt[1];
+
+ /* Last two points of end cap. */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+ }
+
+ /* store computed point2 coordinates as point1 ones of next segment. */
+ copy_v2_v2(s0, s1);
+ /* store stroke's 'natural' normal for next stroke to use */
+ copy_v2_v2(pm, m2);
+ }
+
+ immEnd();
+ immUnbindProgram();
+ }
+}
+
+/* ----- Strokes Drawing ------ */
+
+/* Helper for doing all the checks on whether a stroke can be drawn */
+static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
+{
+ /* skip stroke if it isn't in the right display space for this drawing context */
+ /* 1) 3D Strokes */
+ if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
+ return false;
+
+ /* 2) Screen Space 2D Strokes */
+ if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
+ return false;
+
+ /* 3) Image Space (2D) */
+ if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
+ return false;
+
+ /* skip stroke if it doesn't have any valid data */
+ if ((gps->points == NULL) || (gps->totpoints < 1))
+ return false;
+
+ /* stroke can be drawn */
+ return true;
+}
+
+/* draw a set of strokes */
+static void gp_draw_strokes(
+ bGPdata *UNUSED(gpd), bGPDlayer *UNUSED(gpl), const bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
+ int dflag, bool debug, short lthick, const float color[4])
+{
+ GPU_enable_program_point_size();
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* check if stroke can be drawn */
+ if (gp_can_draw_stroke(gps, dflag) == false) {
+ continue;
+ }
+
+ /* check which stroke-drawer to use */
+ if (dflag & GP_DRAWDATA_ONLY3D) {
+ const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
+ int mask_orig = 0;
+
+ if (no_xray) {
+ glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
+ glDepthMask(0);
+ GPU_depth_test(true);
+
+ /* first arg is normally rv3d->dist, but this isn't
+ * available here and seems to work quite well without */
+ bglPolygonOffset(1.0f, 1.0f);
+ }
+
+ /* 3D Lines - OpenGL primitives-based */
+ if (gps->totpoints == 1) {
+ gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color);
+ }
+ else {
+ gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug, gps->flag,
+ color, gps->flag & GP_STROKE_CYCLIC);
+ }
+
+ if (no_xray) {
+ glDepthMask(mask_orig);
+ GPU_depth_test(false);
+
+ bglPolygonOffset(0.0, 0.0);
+ }
+ }
+ else {
+ /* 2D Strokes... */
+ if (gps->totpoints == 1) {
+ gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color);
+ }
+ else {
+ gp_draw_stroke_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug,
+ offsx, offsy, winx, winy, color);
+ }
+ }
+ }
+
+ GPU_disable_program_point_size();
+}
+
+/* Draw selected verts for strokes being edited */
+static void gp_draw_strokes_edit(
+ bGPdata *gpd, bGPDlayer *gpl, const bGPDframe *gpf,
+ int offsx, int offsy, int winx, int winy,
+ short dflag, short UNUSED(lflag), float alpha)
+{
+ /* if alpha 0 do not draw */
+ if (alpha == 0.0f)
+ return;
+
+ const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0;
+ int mask_orig = 0;
+
+ /* set up depth masks... */
+ if (dflag & GP_DRAWDATA_ONLY3D) {
+ if (no_xray) {
+ glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
+ glDepthMask(0);
+ GPU_depth_test(true);
+
+ /* first arg is normally rv3d->dist, but this isn't
+ * available here and seems to work quite well without */
+ bglPolygonOffset(1.0f, 1.0f);
+ }
+ }
+
+ GPU_enable_program_point_size();
+
+ /* draw stroke verts */
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* check if stroke can be drawn */
+ if (gp_can_draw_stroke(gps, dflag) == false)
+ continue;
+
+ /* Optimisation: only draw points for selected strokes
+ * We assume that selected points can only occur in
+ * strokes that are selected too.
+ */
+ if ((gps->flag & GP_STROKE_SELECT) == 0)
+ continue;
+
+ /* 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;
+ }
+
+ float selectColor[4];
+ UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
+ selectColor[3] = alpha;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos; /* specified later */
+ uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
+ }
+ else {
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR);
+ }
+
+ 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 */
+ immAttrib3f(color, 0.0f, 1.0f, 0.0f);
+ immAttrib1f(size, vsize + 4);
+ }
+ else if (show_direction_hint && (i == gps->totpoints - 1)) {
+ /* end point in red smaller */
+ immAttrib3f(color, 1.0f, 0.0f, 0.0f);
+ immAttrib1f(size, vsize + 1);
+ }
+ else if (pt->flag & GP_SPOINT_SELECT) {
+ immAttrib3fv(color, selectColor);
+ immAttrib1f(size, vsize);
+ }
+ else {
+ immAttrib3fv(color, gpl->color);
+ immAttrib1f(size, bsize);
+ }
+
+ /* then position */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ immVertex3fv(pos, &pt->x);
+ }
+ else {
+ float co[2];
+ gp_calc_2d_stroke_fxy(&pt->x, gps->flag, offsx, offsy, winx, winy, co);
+ immVertex2fv(pos, co);
+ }
+ }
+
+ immEnd();
+ immUnbindProgram();
+ }
+
+ GPU_disable_program_point_size();
+
+ /* clear depth mask */
+ if (dflag & GP_DRAWDATA_ONLY3D) {
+ if (no_xray) {
+ glDepthMask(mask_orig);
+ GPU_depth_test(false);
+
+ bglPolygonOffset(0.0, 0.0);
+#if 0
+ glDisable(GL_POLYGON_OFFSET_LINE);
+ glPolygonOffset(0, 0);
+#endif
+ }
+ }
+}
+
+/* ----- General Drawing ------ */
+
+/* loop over gpencil data layers, drawing them */
+static void gp_draw_data_layers(
+ bGPdata *gpd, int offsx, int offsy, int winx, int winy,
+ int cfra, int dflag, float alpha)
+{
+ float ink[4];
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG);
+ short lthick = gpl->thickness;
+
+ /* apply layer opacity */
+ copy_v3_v3(ink, gpl->color);
+ ink[3] = gpl->opacity;
+
+ /* don't draw layer if hidden */
+ if (gpl->flag & GP_LAYER_HIDE)
+ continue;
+
+ /* get frame to draw */
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra, 0);
+ if (gpf == NULL)
+ continue;
+
+ /* set basic stroke thickness */
+ GPU_line_width(lthick);
+
+ /* Add layer drawing settings to the set of "draw flags"
+ * NOTE: If the setting doesn't apply, it *must* be cleared,
+ * as dflag's carry over from the previous layer
+ */
+#define GP_DRAWFLAG_APPLY(condition, draw_flag_value) { \
+ if (condition) dflag |= (draw_flag_value); \
+ else dflag &= ~(draw_flag_value); \
+ } (void)0
+
+ /* xray... */
+ GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_NO_XRAY), GP_DRAWDATA_NO_XRAY);
+
+#undef GP_DRAWFLAG_APPLY
+
+
+ /* draw the strokes already in active frame */
+ gp_draw_strokes(gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, debug, lthick, ink);
+
+ /* Draw verts of selected strokes
+ * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
+ * - locked layers can't be edited, so there's no point showing these verts
+ * as they will have no bearings on what gets edited
+ * - only show when in editmode, since operators shouldn't work otherwise
+ * (NOTE: doing it this way means that the toggling editmode shows visible change immediately)
+ */
+ /* XXX: perhaps we don't want to show these when users are drawing... */
+ if ((G.f & G_RENDER_OGL) == 0 &&
+ (gpl->flag & GP_LAYER_LOCKED) == 0 &&
+ (gpd->flag & GP_DATA_STROKE_EDITMODE))
+ {
+ gp_draw_strokes_edit(gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, alpha);
+ }
+
+ /* 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 (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) &&
+ (gpf->flag & GP_FRAME_PAINT))
+ {
+ /* Buffer stroke needs to be drawn with a different linestyle
+ * to help differentiate them from normal strokes.
+ *
+ * It should also be noted that sbuffer contains temporary point types
+ * i.e. tGPspoints NOT bGPDspoints
+ */
+ gp_draw_stroke_buffer(gpd->runtime.sbuffer,
+ gpd->runtime.sbuffer_size, lthick,
+ dflag, gpd->runtime.sbuffer_sflag, ink);
+ }
+ }
+}
+
+/* draw a short status message in the top-right corner */
+static void gp_draw_status_text(const bGPdata *gpd, ARegion *ar)
+{
+ rcti rect;
+
+ /* Cannot draw any status text when drawing OpenGL Renders */
+ if (G.f & G_RENDER_OGL)
+ return;
+
+ /* Get bounds of region - Necessary to avoid problems with region overlap */
+ ED_region_visible_rect(ar, &rect);
+
+ /* 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);
+ }
+}
+
+/* draw grease-pencil datablock */
+static void gp_draw_data(
+ bGPdata *gpd, int offsx, int offsy, int winx, int winy,
+ int cfra, int dflag, float alpha)
+{
+ /* turn on smooth lines (i.e. anti-aliasing) */
+ GPU_line_smooth(true);
+
+ /* turn on alpha-blending */
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+
+ /* draw! */
+ gp_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
+
+ /* turn off alpha blending, then smooth lines */
+ GPU_blend(false); // alpha blending
+ GPU_line_smooth(false); // smooth lines
+}
+
+/* if we have strokes for scenes (3d view)/clips (movie clip editor)
+ * and objects/tracks, multiple data blocks have to be drawn */
+static void gp_draw_data_all(
+ Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy,
+ int cfra, int dflag, const char spacetype)
+{
+ bGPdata *gpd_source = NULL;
+ float alpha = 1.0f;
+
+ if (scene) {
+ if (spacetype == SPACE_VIEW3D) {
+ gpd_source = (scene->gpd ? scene->gpd : NULL);
+ }
+ else if (spacetype == SPACE_CLIP && scene->clip) {
+ /* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */
+ gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL);
+ }
+
+ if (gpd_source) {
+ gp_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ }
+ }
+
+ /* scene/clip data has already been drawn, only object/track data is drawn here
+ * if gpd_source == gpd, we don't have any object/track data and we can skip */
+ if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
+ gp_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ }
+}
+
+/* ----- Grease Pencil Sketches Drawing API ------ */
+
+/* ............................
+ * XXX
+ * We need to review the calls below, since they may be/are not that suitable for
+ * the new ways that we intend to be drawing data...
+ * ............................ */
+
+/* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
+void ED_gpencil_draw_2dimage(const bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+
+ int offsx, offsy, sizex, sizey;
+ int dflag = GP_DRAWDATA_NOSTATUS;
+
+ bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX
+ if (gpd == NULL) return;
+
+ /* calculate rect */
+ switch (sa->spacetype) {
+ case SPACE_IMAGE: /* image */
+ case SPACE_CLIP: /* clip */
+ {
+ /* just draw using standard scaling (settings here are currently ignored anyways) */
+ /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
+ offsx = 0;
+ offsy = 0;
+ sizex = ar->winx;
+ sizey = ar->winy;
+
+ wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax);
+
+ dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK;
+ break;
+ }
+ case SPACE_SEQ: /* sequence */
+ {
+ /* just draw using standard scaling (settings here are currently ignored anyways) */
+ offsx = 0;
+ offsy = 0;
+ sizex = ar->winx;
+ sizey = ar->winy;
+
+ /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated
+ * and everything moved to standard View2d
+ */
+ dflag |= GP_DRAWDATA_ONLYV2D;
+ break;
+ }
+ default: /* for spacetype not yet handled */
+ offsx = 0;
+ offsy = 0;
+ sizex = ar->winx;
+ sizey = ar->winy;
+
+ dflag |= GP_DRAWDATA_ONLYI2D;
+ break;
+ }
+
+ if (ED_screen_animation_playing(wm)) {
+ /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses)
+ * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes)
+ */
+ dflag |= GP_DRAWDATA_NO_ONIONS;
+ }
+
+ /* draw it! */
+ gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype);
+}
+
+/* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly
+ * Note: this gets called twice - first time with onlyv2d=true to draw 'canvas' strokes,
+ * second time with onlyv2d=false for screen-aligned strokes */
+void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ int dflag = 0;
+
+ /* check that we have grease-pencil stuff to draw */
+ if (sa == NULL) return;
+ bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX
+ if (gpd == NULL) return;
+
+ /* special hack for Image Editor */
+ /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
+ if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP))
+ dflag |= GP_DRAWDATA_IEDITHACK;
+
+ /* draw it! */
+ if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
+ if (ED_screen_animation_playing(wm)) dflag |= GP_DRAWDATA_NO_ONIONS;
+
+ gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype);
+
+ /* draw status text (if in screen/pixel-space) */
+ if (!onlyv2d) {
+ gp_draw_status_text(gpd, ar);
+ }
+}
+
+
+/* draw annotations sketches to specified 3d-view assuming that matrices are already set correctly
+ * Note: this gets called twice - first time with only3d=true to draw 3d-strokes,
+ * second time with only3d=false for screen-aligned strokes */
+void ED_gpencil_draw_view3d_annotations(
+ Scene *scene, struct Depsgraph *depsgraph,
+ View3D *v3d, ARegion *ar,
+ bool only3d)
+{
+ int dflag = 0;
+ RegionView3D *rv3d = ar->regiondata;
+ int offsx, offsy, winx, winy;
+
+ /* check that we have grease-pencil stuff to draw */
+ /* XXX: Hardcoded reference here may get out of sync if we change how we fetch annotation data */
+ bGPdata *gpd = scene->gpd;
+ if (gpd == NULL) return;
+
+ /* when rendering to the offscreen buffer we don't want to
+ * deal with the camera border, otherwise map the coords to the camera border. */
+ if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
+ rctf rectf;
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */
+
+ offsx = round_fl_to_int(rectf.xmin);
+ offsy = round_fl_to_int(rectf.ymin);
+ winx = round_fl_to_int(rectf.xmax - rectf.xmin);
+ winy = round_fl_to_int(rectf.ymax - rectf.ymin);
+ }
+ else {
+ offsx = 0;
+ offsy = 0;
+ winx = ar->winx;
+ winy = ar->winy;
+ }
+
+ /* set flags */
+ if (only3d) {
+ /* 3D strokes/3D space:
+ * - only 3D space points
+ * - don't status text either (as it's the wrong space)
+ */
+ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
+ }
+
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ /* don't draw status text when "only render" flag is set */
+ dflag |= GP_DRAWDATA_NOSTATUS;
+ }
+
+ /* draw it! */
+ gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
+}
+
+#if 0 // XXX: Reinstate, after renaming the functions
+
+void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
+{
+ int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D;
+
+ gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype);
+}
+
+#endif
+
+/* ************************************************** */
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
new file mode 100644
index 00000000000..6325052fccd
--- /dev/null
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -0,0 +1,2382 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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/2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/gpencil/annotate_paint.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_geom.h"
+
+#include "BLT_translation.h"
+
+#include "PIL_time.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+#include "BKE_screen.h"
+#include "BKE_tracking.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_clip.h"
+
+#include "BIF_glutil.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_state.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "gpencil_intern.h"
+
+/* ******************************************* */
+/* 'Globals' and Defines */
+
+/* values for tGPsdata->status */
+typedef enum eGPencil_PaintStatus {
+ GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
+ GP_STATUS_PAINTING, /* a stroke is in progress */
+ GP_STATUS_ERROR, /* something wasn't correctly set up */
+ GP_STATUS_DONE /* painting done */
+} eGPencil_PaintStatus;
+
+/* Return flags for adding points to stroke buffer */
+typedef enum eGP_StrokeAdd_Result {
+ GP_STROKEADD_INVALID = -2, /* error occurred - insufficient info to do so */
+ GP_STROKEADD_OVERFLOW = -1, /* error occurred - cannot fit any more points */
+ GP_STROKEADD_NORMAL, /* point was successfully added */
+ GP_STROKEADD_FULL /* cannot add any more points to buffer */
+} eGP_StrokeAdd_Result;
+
+/* Runtime flags */
+typedef enum eGPencil_PaintFlags {
+ GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
+ GP_PAINTFLAG_STROKEADDED = (1 << 1),
+ GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
+ GP_PAINTFLAG_SELECTMASK = (1 << 3),
+} eGPencil_PaintFlags;
+
+
+/* Temporary 'Stroke' Operation data
+ * "p" = op->customdata
+ */
+typedef struct tGPsdata {
+ Main *bmain;
+ Scene *scene; /* current scene from context */
+ struct Depsgraph *depsgraph;
+
+ wmWindow *win; /* window where painting originated */
+ ScrArea *sa; /* area where painting originated */
+ ARegion *ar; /* region where painting originated */
+ View2D *v2d; /* needed for GP_STROKE_2DSPACE */
+ rctf *subrect; /* for using the camera rect within the 3d view */
+ rctf subrect_data;
+
+ GP_SpaceConversion gsc; /* settings to pass to gp_points_to_xy() */
+
+ PointerRNA ownerPtr; /* pointer to owner of gp-datablock */
+ bGPdata *gpd; /* gp-datablock layer comes from */
+ bGPDlayer *gpl; /* layer we're working on */
+ bGPDframe *gpf; /* frame we're working on */
+
+ char *align_flag; /* projection-mode flags (toolsettings - eGPencil_Placement_Flags) */
+
+ eGPencil_PaintStatus status; /* current status of painting */
+ eGPencil_PaintModes paintmode; /* mode for painting */
+ eGPencil_PaintFlags flags; /* flags that can get set during runtime (eGPencil_PaintFlags) */
+
+ short radius; /* radius of influence for eraser */
+
+ int mval[2]; /* current mouse-position */
+ int mvalo[2]; /* previous recorded mouse-position */
+
+ float pressure; /* current stylus pressure */
+ float opressure; /* previous stylus pressure */
+
+ /* These need to be doubles, as (at least under unix) they are in seconds since epoch,
+ * float (and its 7 digits precision) is definitively not enough here!
+ * double, with its 15 digits precision, ensures us millisecond precision for a few centuries at least.
+ */
+ double inittime; /* Used when converting to path */
+ double curtime; /* Used when converting to path */
+ double ocurtime; /* Used when converting to path */
+
+ float imat[4][4]; /* inverted transformation matrix applying when converting coords from screen-space
+ * to region space */
+ float mat[4][4];
+
+ float custom_color[4]; /* custom color - hack for enforcing a particular color for track/mask editing */
+
+ void *erasercursor; /* radial cursor data for drawing eraser */
+
+ short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */
+ int lock_axis; /* lock drawing to one axis */
+
+ short keymodifier; /* key used for invoking the operator */
+} tGPsdata;
+
+/* ------ */
+
+/* Macros for accessing sensitivity thresholds... */
+/* minimum number of pixels mouse should move before new point created */
+#define MIN_MANHATTEN_PX (U.gp_manhattendist)
+/* minimum length of new segment before new point can be added */
+#define MIN_EUCLIDEAN_PX (U.gp_euclideandist)
+
+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);
+ p->flags |= GP_PAINTFLAG_STROKEADDED;
+}
+
+/* ------ */
+/* Forward defines for some functions... */
+
+static void gp_session_validatebuffer(tGPsdata *p);
+
+/* ******************************************* */
+/* Context Wrangling... */
+
+/* check if context is suitable for drawing */
+static bool gpencil_draw_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) {
+ /* check if Grease Pencil isn't already running */
+ if (ED_gpencil_session_active() == 0)
+ return 1;
+ else
+ CTX_wm_operator_poll_msg_set(C, "Annotation operator is already active");
+ }
+ 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;
+}
+
+/* check if projecting strokes into 3d-geometry in the 3D-View */
+static bool gpencil_project_check(tGPsdata *p)
+{
+ bGPdata *gpd = p->gpd;
+ return ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)));
+}
+
+/* ******************************************* */
+/* Calculations/Conversions */
+
+/* Utilities --------------------------------- */
+
+/* get the reference point for stroke-point conversions */
+static void gp_get_3d_reference(tGPsdata *p, float vec[3])
+{
+ View3D *v3d = p->sa->spacedata.first;
+ const float *fp = ED_view3d_cursor3d_get(p->scene, v3d)->location;
+
+ /* use 3D-cursor */
+ copy_v3_v3(vec, fp);
+}
+
+/* Stroke Editing ---------------------------- */
+
+/* check if the current mouse position is suitable for adding a new point */
+static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2])
+{
+ int dx = abs(mval[0] - pmval[0]);
+ int dy = abs(mval[1] - pmval[1]);
+
+ /* if buffer is empty, just let this go through (i.e. so that dots will work) */
+ if (p->gpd->runtime.sbuffer_size == 0)
+ return true;
+
+ /* check if mouse moved at least certain distance on both axes (best case)
+ * - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand
+ */
+ else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX))
+ return true;
+
+ /* check if the distance since the last point is significant enough
+ * - prevents points being added too densely
+ * - distance here doesn't use sqrt to prevent slowness... we should still be safe from overflows though
+ */
+ else if ((dx * dx + dy * dy) > MIN_EUCLIDEAN_PX * MIN_EUCLIDEAN_PX)
+ return true;
+
+ /* mouse 'didn't move' */
+ else
+ return false;
+}
+
+/* reproject the points of the stroke to a plane locked to axis to avoid stroke offset */
+static void gp_project_points_to_plane(RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis)
+{
+ float plane_normal[3];
+ float vn[3];
+
+ float ray[3];
+ float rpoint[3];
+
+ /* normal vector for a plane locked to axis */
+ zero_v3(plane_normal);
+ plane_normal[axis] = 1.0f;
+
+ /* Reproject the points in the plane */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+
+ /* get a vector from the point with the current view direction of the viewport */
+ ED_view3d_global_to_vector(rv3d, &pt->x, vn);
+
+ /* calculate line extrem point to create a ray that cross the plane */
+ mul_v3_fl(vn, -50.0f);
+ add_v3_v3v3(ray, &pt->x, vn);
+
+ /* if the line never intersect, the point is not changed */
+ if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
+ copy_v3_v3(&pt->x, rpoint);
+ }
+ }
+}
+
+/* reproject stroke to plane locked to axis in 3d cursor location */
+static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps)
+{
+ bGPdata *gpd = p->gpd;
+ float origin[3];
+ float cursor[3];
+ RegionView3D *rv3d = p->ar->regiondata;
+
+ /* verify the stroke mode is CURSOR 3d space mode */
+ if ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) == 0) {
+ return;
+ }
+ if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
+ return;
+ }
+ if ((*p->align_flag & GP_PROJECT_DEPTH_VIEW) || (*p->align_flag & GP_PROJECT_DEPTH_STROKE)) {
+ return;
+ }
+
+ /* get 3d cursor and set origin for locked axis only. Uses axis-1 because the enum for XYZ start with 1 */
+ gp_get_3d_reference(p, cursor);
+ zero_v3(origin);
+ origin[p->lock_axis - 1] = cursor[p->lock_axis - 1];
+
+ gp_project_points_to_plane(rv3d, gps, origin, p->lock_axis - 1);
+}
+
+/* convert screen-coordinates to buffer-coordinates */
+/* XXX this method needs a total overhaul! */
+static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3], float *depth)
+{
+ bGPdata *gpd = p->gpd;
+
+ /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
+ if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
+ if (gpencil_project_check(p) && (ED_view3d_autodist_simple(p->ar, mval, out, 0, depth))) {
+ /* projecting onto 3D-Geometry
+ * - nothing more needs to be done here, since view_autodist_simple() has already done it
+ */
+ }
+ else {
+ float mval_prj[2];
+ float rvec[3], dvec[3];
+ float mval_f[2] = {UNPACK2(mval)};
+ float zfac;
+
+ /* Current method just converts each point in screen-coordinates to
+ * 3D-coordinates using the 3D-cursor as reference. In general, this
+ * works OK, but it could of course be improved.
+ *
+ * TODO:
+ * - investigate using nearest point(s) on a previous stroke as
+ * reference point instead or as offset, for easier stroke matching
+ */
+
+ gp_get_3d_reference(p, rvec);
+ zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL);
+
+ if (ED_view3d_project_float_global(p->ar, 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(p->ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(out, rvec, dvec);
+ }
+ else {
+ zero_v3(out);
+ }
+ }
+ }
+
+ /* 2d - on 'canvas' (assume that p->v2d is set) */
+ else if ((gpd->runtime.sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) {
+ UI_view2d_region_to_view(p->v2d, mval[0], mval[1], &out[0], &out[1]);
+ mul_v3_m4v3(out, p->imat, out);
+ }
+
+ /* 2d - relative to screen (viewport area) */
+ else {
+ if (p->subrect == NULL) { /* normal 3D view */
+ out[0] = (float)(mval[0]) / (float)(p->ar->winx) * 100;
+ out[1] = (float)(mval[1]) / (float)(p->ar->winy) * 100;
+ }
+ else { /* camera view, use subrect */
+ out[0] = ((mval[0] - p->subrect->xmin) / BLI_rctf_size_x(p->subrect)) * 100;
+ out[1] = ((mval[1] - p->subrect->ymin) / BLI_rctf_size_y(p->subrect)) * 100;
+ }
+ }
+}
+
+/* add current stroke-point to buffer (returns whether point was successfully added) */
+static short gp_stroke_addpoint(
+ tGPsdata *p, const int mval[2], float pressure, double curtime)
+{
+ bGPdata *gpd = p->gpd;
+ tGPspoint *pt;
+ ToolSettings *ts = p->scene->toolsettings;
+
+ /* check painting mode */
+ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
+ /* straight lines only - i.e. only store start and end point in buffer */
+ if (gpd->runtime.sbuffer_size == 0) {
+ /* first point in buffer (start point) */
+ pt = (tGPspoint *)(gpd->runtime.sbuffer);
+
+ /* store settings */
+ copy_v2_v2_int(&pt->x, mval);
+ pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->strength = 1.0f;
+ pt->time = (float)(curtime - p->inittime);
+
+ /* increment buffer size */
+ gpd->runtime.sbuffer_size++;
+ }
+ else {
+ /* just reset the endpoint to the latest value
+ * - assume that pointers for this are always valid...
+ */
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
+
+ /* store settings */
+ copy_v2_v2_int(&pt->x, mval);
+ pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->strength = 1.0f;
+ pt->time = (float)(curtime - p->inittime);
+
+ /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
+ gpd->runtime.sbuffer_size = 2;
+ }
+
+ /* can keep carrying on this way :) */
+ return GP_STROKEADD_NORMAL;
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW) { /* normal drawing */
+ /* check if still room in buffer */
+ if (gpd->runtime.sbuffer_size >= GP_STROKE_BUFFER_MAX)
+ return GP_STROKEADD_OVERFLOW;
+
+ /* get pointer to destination point */
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size);
+
+ /* store settings */
+ copy_v2_v2_int(&pt->x, mval);
+ pt->pressure = pressure;
+ pt->strength = 1.0f; /* unused for annotations, but initialise for easier conversions to GP Object */
+
+ /* point time */
+ pt->time = (float)(curtime - p->inittime);
+
+ /* increment counters */
+ gpd->runtime.sbuffer_size++;
+
+ /* check if another operation can still occur */
+ if (gpd->runtime.sbuffer_size == GP_STROKE_BUFFER_MAX)
+ return GP_STROKEADD_FULL;
+ else
+ return GP_STROKEADD_NORMAL;
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+ /* get pointer to destination point */
+ pt = (tGPspoint *)(gpd->runtime.sbuffer);
+
+ /* store settings */
+ copy_v2_v2_int(&pt->x, mval);
+ pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
+ 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;
+
+ /* first time point is adding to temporary buffer -- need to allocate new point in stroke */
+ if (gpd->runtime.sbuffer_size == 0) {
+ gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ gps->totpoints++;
+ }
+
+ pts = &gps->points[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 *v3d = p->sa->spacedata.first;
+
+ view3d_region_operator_needs_opengl(p->win, p->ar);
+ ED_view3d_autodist_init(
+ p->depsgraph, p->ar, v3d, (ts->annotate_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);
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, gps);
+ }
+
+ /* copy pressure and time */
+ pts->pressure = pt->pressure;
+ pts->strength = pt->strength;
+ pts->time = pt->time;
+
+ /* force fill recalc */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ }
+
+ /* increment counters */
+ if (gpd->runtime.sbuffer_size == 0)
+ gpd->runtime.sbuffer_size++;
+
+ return GP_STROKEADD_NORMAL;
+ }
+
+ /* return invalid state for now... */
+ return GP_STROKEADD_INVALID;
+}
+
+/* simplify a stroke (in buffer) before storing it
+ * - applies a reverse Chaikin filter
+ * - code adapted from etch-a-ton branch
+ */
+static void gp_stroke_simplify(tGPsdata *p)
+{
+ bGPdata *gpd = p->gpd;
+ tGPspoint *old_points = (tGPspoint *)gpd->runtime.sbuffer;
+ short num_points = gpd->runtime.sbuffer_size;
+ short flag = gpd->runtime.sbuffer_sflag;
+ short i, j;
+
+ /* only simplify if simplification is enabled, and we're not doing a straight line */
+ if (!(U.gp_settings & GP_PAINT_DOSIMPLIFY) || (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT))
+ return;
+
+ /* don't simplify if less than 4 points in buffer */
+ if ((num_points <= 4) || (old_points == NULL))
+ return;
+
+ /* clear buffer (but don't free mem yet) so that we can write to it
+ * - firstly set sbuffer to NULL, so a new one is allocated
+ * - secondly, reset flag after, as it gets cleared auto
+ */
+ gpd->runtime.sbuffer = NULL;
+ gp_session_validatebuffer(p);
+ gpd->runtime.sbuffer_sflag = flag;
+
+/* macro used in loop to get position of new point
+ * - used due to the mixture of datatypes in use here
+ */
+#define GP_SIMPLIFY_AVPOINT(offs, sfac) \
+ { \
+ co[0] += (float)(old_points[offs].x * sfac); \
+ co[1] += (float)(old_points[offs].y * sfac); \
+ pressure += old_points[offs].pressure * sfac; \
+ time += old_points[offs].time * sfac; \
+ } (void)0
+
+ /* XXX Here too, do not lose start and end points! */
+ gp_stroke_addpoint(p, &old_points->x, old_points->pressure, p->inittime + (double)old_points->time);
+ for (i = 0, j = 0; i < num_points; i++) {
+ if (i - j == 3) {
+ float co[2], pressure, time;
+ int mco[2];
+
+ /* initialize values */
+ co[0] = 0.0f;
+ co[1] = 0.0f;
+ pressure = 0.0f;
+ time = 0.0f;
+
+ /* using macro, calculate new point */
+ GP_SIMPLIFY_AVPOINT(j, -0.25f);
+ GP_SIMPLIFY_AVPOINT(j + 1, 0.75f);
+ GP_SIMPLIFY_AVPOINT(j + 2, 0.75f);
+ GP_SIMPLIFY_AVPOINT(j + 3, -0.25f);
+
+ /* set values for adding */
+ mco[0] = (int)co[0];
+ mco[1] = (int)co[1];
+
+ /* ignore return values on this... assume to be ok for now */
+ gp_stroke_addpoint(p, mco, pressure, p->inittime + (double)time);
+
+ j += 2;
+ }
+ }
+ gp_stroke_addpoint(p, &old_points[num_points - 1].x, old_points[num_points - 1].pressure,
+ p->inittime + (double)old_points[num_points - 1].time);
+
+ /* free old buffer */
+ MEM_freeN(old_points);
+}
+
+/* make a new stroke from the buffer data */
+static void gp_stroke_newfrombuffer(tGPsdata *p)
+{
+ bGPdata *gpd = p->gpd;
+ bGPDlayer *gpl = p->gpl;
+ bGPDstroke *gps;
+ bGPDspoint *pt;
+ tGPspoint *ptc;
+ ToolSettings *ts = p->scene->toolsettings;
+
+ int i, totelem;
+ /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
+ int depth_margin = (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
+
+ /* get total number of points to allocate space for
+ * - drawing straight-lines only requires the endpoints
+ */
+ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT)
+ totelem = (gpd->runtime.sbuffer_size >= 2) ? 2 : gpd->runtime.sbuffer_size;
+ else
+ totelem = gpd->runtime.sbuffer_size;
+
+ /* exit with error if no valid points from this stroke */
+ if (totelem == 0) {
+ if (G.debug & G_DEBUG)
+ printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", gpd->runtime.sbuffer_size);
+ 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) {
+ 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 = gpl->thickness;
+ 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_CACHES;
+
+ /* allocate enough memory for a continuous array for storage points */
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->tot_triangles = 0;
+
+ /* set pointer to first non-initialized point */
+ pt = gps->points + (gps->totpoints - totelem);
+
+ /* copy points from the buffer to the stroke */
+ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
+ /* straight lines only -> only endpoints */
+ {
+ /* first point */
+ ptc = gpd->runtime.sbuffer;
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, 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;
+
+ pt++;
+ }
+
+ if (totelem == 2) {
+ /* last point if applicable */
+ ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_size - 1);
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, 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;
+ }
+ }
+ 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);
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, gps);
+ }
+ /* copy pressure and time */
+ pt->pressure = ptc->pressure;
+ pt->strength = ptc->strength;
+ pt->time = ptc->time;
+ }
+ else {
+ float *depth_arr = NULL;
+
+ /* get an array of depths, far depths are blended */
+ if (gpencil_project_check(p)) {
+ int mval[2], mval_prev[2] = { 0 };
+ int interp_depth = 0;
+ int found_depth = 0;
+
+ depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_size, "depth_points");
+
+ for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size; i++, ptc++, pt++) {
+ copy_v2_v2_int(mval, &ptc->x);
+
+ if ((ED_view3d_autodist_depth(p->ar, mval, depth_margin, depth_arr + i) == 0) &&
+ (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
+ {
+ interp_depth = true;
+ }
+ else {
+ found_depth = true;
+ }
+
+ copy_v2_v2_int(mval_prev, mval);
+ }
+
+ if (found_depth == false) {
+ /* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
+ for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--)
+ depth_arr[i] = 0.9999f;
+ }
+ else {
+ if (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) {
+ /* remove all info between the valid endpoints */
+ int first_valid = 0;
+ int last_valid = 0;
+
+ for (i = 0; i < gpd->runtime.sbuffer_size; i++) {
+ if (depth_arr[i] != FLT_MAX)
+ break;
+ }
+ first_valid = i;
+
+ for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--) {
+ if (depth_arr[i] != FLT_MAX)
+ break;
+ }
+ last_valid = i;
+
+ /* invalidate non-endpoints, so only blend between first and last */
+ for (i = first_valid + 1; i < last_valid; i++)
+ depth_arr[i] = FLT_MAX;
+
+ interp_depth = true;
+ }
+
+ if (interp_depth) {
+ interp_sparse_array(depth_arr, gpd->runtime.sbuffer_size, FLT_MAX);
+ }
+ }
+ }
+
+
+ pt = gps->points;
+
+ /* convert all points (normal behavior) */
+ for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size && ptc; i++, ptc++, pt++) {
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
+
+ /* 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 axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, gps);
+ }
+
+ if (depth_arr)
+ MEM_freeN(depth_arr);
+ }
+
+ /* add stroke to frame */
+ BLI_addtail(&p->gpf->strokes, gps);
+ gp_stroke_added_enable(p);
+}
+
+/* --- 'Eraser' for 'Paint' Tool ------ */
+
+/* helper to free a stroke
+ * NOTE: gps->dvert and gps->triangles should be NULL, but check anyway for good measure
+ */
+static void gp_free_stroke(bGPdata *UNUSED(gpd), bGPDframe *gpf, bGPDstroke *gps)
+{
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+
+ if (gps->triangles) {
+ MEM_freeN(gps->triangles);
+ }
+
+ BLI_freelinkN(&gpf->strokes, gps);
+}
+
+
+/* which which point is infront (result should only be used for comparison) */
+static float view3d_point_depth(const RegionView3D *rv3d, const float co[3])
+{
+ if (rv3d->is_persp) {
+ return ED_view3d_calc_zfac(rv3d, co, NULL);
+ }
+ else {
+ return -dot_v3v3(rv3d->viewinv[2], co);
+ }
+}
+
+/* only erase stroke points that are visible (3d view) */
+static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y)
+{
+ if ((p->sa->spacetype == SPACE_VIEW3D) &&
+ (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH))
+ {
+ RegionView3D *rv3d = p->ar->regiondata;
+ const int mval[2] = {x, y};
+ float mval_3d[3];
+
+ if (ED_view3d_autodist_simple(p->ar, mval, mval_3d, 0, NULL)) {
+ const float depth_mval = view3d_point_depth(rv3d, mval_3d);
+ const float depth_pt = view3d_point_depth(rv3d, &pt->x);
+
+ if (depth_pt > depth_mval) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/* eraser tool - evaluation per stroke */
+/* TODO: this could really do with some optimization (KD-Tree/BVH?) */
+static void gp_stroke_eraser_dostroke(tGPsdata *p,
+ bGPDframe *gpf, bGPDstroke *gps,
+ const int mval[2], const int mvalo[2],
+ const int radius, const rcti *rect)
+{
+ bGPDspoint *pt1, *pt2;
+ int pc1[2] = {0};
+ int pc2[2] = {0};
+ int i;
+
+ if (gps->totpoints == 0) {
+ /* just free stroke */
+ gp_free_stroke(p->gpd, gpf, gps);
+ }
+ else if (gps->totpoints == 1) {
+ /* only process if it hasn't been masked out... */
+ if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
+ gp_point_to_xy(&p->gsc, gps, gps->points, &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])) {
+ /* only check if point is inside */
+ if (len_v2v2_int(mval, pc1) <= radius) {
+ /* free stroke */
+ gp_free_stroke(p->gpd, gpf, gps);
+ }
+ }
+ }
+ }
+ else {
+ /* Perform culling? */
+ bool do_cull = false;
+
+ /* Clear Tags
+ *
+ * Note: It's better this way, as we are sure that
+ * we don't miss anything, though things will be
+ * slightly slower as a result
+ */
+ for (i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ pt->flag &= ~GP_SPOINT_TAG;
+ }
+
+ /* First Pass: Loop over the points in the stroke
+ * 1) Thin out parts of the stroke under the brush
+ * 2) Tag "too thin" parts for removal (in second pass)
+ */
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+ /* get points to work with */
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+
+ /* only process if it hasn't been masked out... */
+ if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
+ continue;
+
+ gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
+ gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
+
+ /* Check that point segment of the boundbox of the eraser 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
+ * eraser region (either within stroke painted, or on its lines)
+ * - this assumes that linewidth is irrelevant
+ */
+ if (gp_stroke_inside_circle(mval, mvalo, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ if ((gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
+ (gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false))
+ {
+ /* Edge is affected - Check individual points now */
+ if (len_v2v2_int(mval, pc1) <= radius) {
+ pt1->flag |= GP_SPOINT_TAG;
+ }
+ if (len_v2v2_int(mval, pc2) <= radius) {
+ pt2->flag |= GP_SPOINT_TAG;
+ }
+ do_cull = true;
+ }
+ }
+ }
+ }
+
+ /* Second Pass: Remove any points that are tagged */
+ if (do_cull) {
+ gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false);
+ }
+ }
+}
+
+/* erase strokes which fall under the eraser strokes */
+static void gp_stroke_doeraser(tGPsdata *p)
+{
+ bGPDframe *gpf = p->gpf;
+ bGPDstroke *gps, *gpn;
+ rcti rect;
+
+ /* rect is rectangle of eraser */
+ rect.xmin = p->mval[0] - p->radius;
+ rect.ymin = p->mval[1] - p->radius;
+ rect.xmax = p->mval[0] + p->radius;
+ rect.ymax = p->mval[1] + p->radius;
+
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) {
+ View3D *v3d = p->sa->spacedata.first;
+ view3d_region_operator_needs_opengl(p->win, p->ar);
+ ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, 0);
+ }
+ }
+
+ /* loop over strokes of active layer only (session init already took care of ensuring validity),
+ * checking segments for intersections to remove
+ */
+ for (gps = gpf->strokes.first; gps; gps = gpn) {
+ gpn = gps->next;
+ /* 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, gpf, gps, p->mval, p->mvalo, p->radius, &rect);
+ }
+ }
+}
+
+/* ******************************************* */
+/* Sketching Operator */
+
+/* clear the session buffers (call this before AND after a paint operation) */
+static void gp_session_validatebuffer(tGPsdata *p)
+{
+ bGPdata *gpd = p->gpd;
+
+ /* clear memory of buffer (or allocate it if starting a new session) */
+ if (gpd->runtime.sbuffer) {
+ /* printf("\t\tGP - reset sbuffer\n"); */
+ memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
+ }
+ else {
+ /* printf("\t\tGP - allocate sbuffer\n"); */
+ gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
+ }
+
+ /* reset indices */
+ gpd->runtime.sbuffer_size = 0;
+
+ /* reset flags */
+ gpd->runtime.sbuffer_sflag = 0;
+
+ /* reset inittime */
+ p->inittime = 0.0;
+}
+
+/* (re)init new painting data */
+static bool gp_session_initdata(bContext *C, tGPsdata *p)
+{
+ Main *bmain = CTX_data_main(C);
+ bGPdata **gpd_ptr = NULL;
+ ScrArea *curarea = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ /* make sure the active view (at the starting time) is a 3d-view */
+ if (curarea == NULL) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: No active view for painting\n");
+ return 0;
+ }
+
+ /* pass on current scene and window */
+ p->bmain = CTX_data_main(C);
+ p->scene = CTX_data_scene(C);
+ p->depsgraph = CTX_data_depsgraph(C);
+ p->win = CTX_wm_window(C);
+
+ unit_m4(p->imat);
+ unit_m4(p->mat);
+
+ switch (curarea->spacetype) {
+ /* supported views first */
+ case SPACE_VIEW3D:
+ {
+ /* View3D *v3d = curarea->spacedata.first; */
+ /* RegionView3D *rv3d = ar->regiondata; */
+
+ /* set current area
+ * - must verify that region data is 3D-view (and not something else)
+ */
+ /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
+ p->sa = curarea;
+ p->ar = ar;
+ p->align_flag = &ts->annotate_v3d_align;
+
+ if (ar->regiondata == NULL) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: 3D-View active region doesn't have any region data, so cannot be drawable\n");
+ return 0;
+ }
+ break;
+ }
+ case SPACE_NODE:
+ {
+ /* SpaceNode *snode = curarea->spacedata.first; */
+
+ /* set current area */
+ p->sa = curarea;
+ p->ar = ar;
+ p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_v2d_align;
+ break;
+ }
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq = curarea->spacedata.first;
+
+ /* set current area */
+ p->sa = curarea;
+ p->ar = ar;
+ p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_seq_align;
+
+ /* check that gpencil data is allowed to be drawn */
+ if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil\n");
+ return 0;
+ }
+ break;
+ }
+ case SPACE_IMAGE:
+ {
+ /* SpaceImage *sima = curarea->spacedata.first; */
+
+ /* set the current area */
+ p->sa = curarea;
+ p->ar = ar;
+ p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_ima_align;
+ break;
+ }
+ case SPACE_CLIP:
+ {
+ SpaceClip *sc = curarea->spacedata.first;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+
+ if (clip == NULL) {
+ p->status = GP_STATUS_ERROR;
+ return false;
+ }
+
+ /* set the current area */
+ p->sa = curarea;
+ p->ar = ar;
+ p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_v2d_align;
+
+ invert_m4_m4(p->imat, sc->unistabmat);
+
+ /* custom color for new layer */
+ p->custom_color[0] = 1.0f;
+ p->custom_color[1] = 0.0f;
+ p->custom_color[2] = 0.5f;
+ p->custom_color[3] = 0.9f;
+
+ if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+ MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
+ MovieTrackingMarker *marker = track ? BKE_tracking_marker_get(track, framenr) : NULL;
+
+ if (marker) {
+ p->imat[3][0] -= marker->pos[0];
+ p->imat[3][1] -= marker->pos[1];
+ }
+ else {
+ p->status = GP_STATUS_ERROR;
+ return false;
+ }
+ }
+
+ invert_m4_m4(p->mat, p->imat);
+ copy_m4_m4(p->gsc.mat, p->mat);
+ break;
+ }
+ /* unsupported views */
+ default:
+ {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: Annotations are not supported in this editor\n");
+ return 0;
+ }
+ }
+
+ /* get gp-data */
+ gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr);
+ if ((gpd_ptr == NULL) || !ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: Current context doesn't allow for any Annotation data\n");
+ return 0;
+ }
+ else {
+ /* if no existing GPencil block exists, add one */
+ if (*gpd_ptr == NULL) {
+ bGPdata *gpd = BKE_gpencil_data_addnew(bmain, "Annotations");
+ *gpd_ptr = gpd;
+
+ /* mark datablock as being used for annotations */
+ gpd->flag |= GP_DATA_ANNOTATIONS;
+
+ /* annotations always in front of all objects */
+ gpd->xray_mode = GP_XRAY_FRONT;
+ }
+ p->gpd = *gpd_ptr;
+ }
+
+ if (ED_gpencil_session_active() == 0) {
+ /* initialize undo stack,
+ * also, existing undo stack would make buffer drawn
+ */
+ gpencil_undo_init(p->gpd);
+ }
+
+ /* clear out buffer (stored in gp-data), in case something contaminated it */
+ gp_session_validatebuffer(p);
+
+ /* lock axis */
+ p->lock_axis = ts->gp_sculpt.lock_axis;
+
+ return 1;
+}
+
+/* init new painting session */
+static tGPsdata *gp_session_initpaint(bContext *C)
+{
+ tGPsdata *p = NULL;
+
+ /* create new context data */
+ p = MEM_callocN(sizeof(tGPsdata), "Annotation Drawing Data");
+
+ gp_session_initdata(C, p);
+
+ /* radius for eraser circle is defined in userprefs now */
+ /* NOTE: we do this here, so that if we exit immediately,
+ * erase size won't get lost
+ */
+ p->radius = U.gp_eraser;
+
+ /* return context data for running paint operator */
+ return p;
+}
+
+/* cleanup after a painting session */
+static void gp_session_cleanup(tGPsdata *p)
+{
+ bGPdata *gpd = (p) ? p->gpd : NULL;
+
+ /* error checking */
+ if (gpd == NULL)
+ return;
+
+ /* free stroke buffer */
+ if (gpd->runtime.sbuffer) {
+ /* printf("\t\tGP - free sbuffer\n"); */
+ MEM_freeN(gpd->runtime.sbuffer);
+ gpd->runtime.sbuffer = NULL;
+ }
+
+ /* clear flags */
+ gpd->runtime.sbuffer_size = 0;
+ gpd->runtime.sbuffer_sflag = 0;
+ p->inittime = 0.0;
+}
+
+static void gp_session_free(tGPsdata *p)
+{
+ MEM_freeN(p);
+}
+
+
+/* init new stroke */
+static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Depsgraph *depsgraph)
+{
+ Scene *scene = p->scene;
+ ToolSettings *ts = scene->toolsettings;
+
+ /* get active layer (or add a new one if non-existent) */
+ p->gpl = BKE_gpencil_layer_getactive(p->gpd);
+ if (p->gpl == NULL) {
+ p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("Note"), true);
+
+ if (p->custom_color[3])
+ copy_v3_v3(p->gpl->color, p->custom_color);
+ }
+ if (p->gpl->flag & GP_LAYER_LOCKED) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: Cannot paint on locked layer\n");
+ return;
+ }
+
+ /* get active frame (add a new one if not matching frame) */
+ if (paintmode == GP_PAINTMODE_ERASER) {
+ /* Eraser mode:
+ * 1) Only allow erasing on the active layer (unlike for 3d-art Grease Pencil),
+ * since we won't be exposing layer locking in the UI
+ * 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;
+
+ if (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;
+ }
+ }
+
+ /* Ensure active frame is set correctly... */
+ p->gpf = p->gpl->actframe;
+
+ /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
+ * (though this is only available in editmode)
+ */
+ if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ if (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) {
+ p->flags |= GP_PAINTFLAG_SELECTMASK;
+ }
+ }
+
+ if (has_layer_to_erase == false) {
+ p->status = GP_STATUS_ERROR;
+ //if (G.debug & G_DEBUG)
+ printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n");
+ return;
+ }
+ }
+ else {
+ /* Drawing Modes - Add a new frame if needed on the active layer */
+ short add_frame_mode = GP_GETFRAME_ADD_NEW;
+
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
+ add_frame_mode = GP_GETFRAME_ADD_COPY;
+ else
+ add_frame_mode = GP_GETFRAME_ADD_NEW;
+
+ p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
+
+ if (p->gpf == NULL) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: No frame created (gpencil_paint_init)\n");
+ return;
+ }
+ else {
+ p->gpf->flag |= GP_FRAME_PAINT;
+ }
+ }
+
+ /* set 'eraser' for this stroke if using eraser */
+ p->paintmode = paintmode;
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_ERASER;
+
+ /* check if we should respect depth while erasing */
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->gpl->flag & GP_LAYER_NO_XRAY) {
+ p->flags |= GP_PAINTFLAG_V3D_ERASER_DEPTH;
+ }
+ }
+ }
+ else {
+ /* disable eraser flags - so that we can switch modes during a session */
+ p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_ERASER;
+
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->gpl->flag & GP_LAYER_NO_XRAY) {
+ p->flags &= ~GP_PAINTFLAG_V3D_ERASER_DEPTH;
+ }
+ }
+ }
+
+ /* set 'initial run' flag, which is only used to denote when a new stroke is starting */
+ p->flags |= GP_PAINTFLAG_FIRSTRUN;
+
+
+ /* when drawing in the camera view, in 2D space, set the subrect */
+ p->subrect = NULL;
+ if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = p->sa->spacedata.first;
+ RegionView3D *rv3d = p->ar->regiondata;
+
+ /* for camera view set the subrect */
+ if (rv3d->persp == RV3D_CAMOB) {
+ ED_view3d_calc_camera_border(p->scene, depsgraph, p->ar, v3d, rv3d, &p->subrect_data, true); /* no shift */
+ p->subrect = &p->subrect_data;
+ }
+ }
+ }
+
+ /* init stroke point space-conversion settings... */
+ p->gsc.gpd = p->gpd;
+ p->gsc.gpl = p->gpl;
+
+ p->gsc.sa = p->sa;
+ p->gsc.ar = p->ar;
+ p->gsc.v2d = p->v2d;
+
+ p->gsc.subrect_data = p->subrect_data;
+ p->gsc.subrect = p->subrect;
+
+ copy_m4_m4(p->gsc.mat, p->mat);
+
+
+ /* check if points will need to be made in view-aligned space */
+ if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
+ switch (p->sa->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
+ break;
+ }
+ case SPACE_NODE:
+ {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE;
+ break;
+ }
+ case SPACE_SEQ:
+ {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE;
+ break;
+ }
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima = (SpaceImage *)p->sa->spacedata.first;
+
+ /* only set these flags if the image editor doesn't have an image active,
+ * otherwise user will be confused by strokes not appearing after they're drawn
+ *
+ * Admittedly, this is a bit hacky, but it works much nicer from an ergonomic standpoint!
+ */
+ if (ELEM(NULL, sima, sima->image)) {
+ /* make strokes be drawn in screen space */
+ p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_2DSPACE;
+ *(p->align_flag) &= ~GP_PROJECT_VIEWSPACE;
+ }
+ else {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE;
+ }
+ break;
+ }
+ case SPACE_CLIP:
+ {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE;
+ break;
+ }
+ }
+ }
+}
+
+/* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
+static void gp_paint_strokeend(tGPsdata *p)
+{
+ ToolSettings *ts = p->scene->toolsettings;
+ /* for surface sketching, need to set the right OpenGL context stuff so that
+ * the conversions will project the values correctly...
+ */
+ if (gpencil_project_check(p)) {
+ View3D *v3d = p->sa->spacedata.first;
+
+ /* need to restore the original projection settings before packing up */
+ view3d_region_operator_needs_opengl(p->win, p->ar);
+ ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
+ }
+
+ /* check if doing eraser or not */
+ if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
+ /* simplify stroke before transferring? */
+ gp_stroke_simplify(p);
+
+ /* transfer stroke to frame */
+ gp_stroke_newfrombuffer(p);
+ }
+
+ /* clean up buffer now */
+ gp_session_validatebuffer(p);
+}
+
+/* finish off stroke painting operation */
+static void gp_paint_cleanup(tGPsdata *p)
+{
+ /* p->gpd==NULL happens when stroke failed to initialize,
+ * for example when GP is hidden in current space (sergey)
+ */
+ if (p->gpd) {
+ /* finish off a stroke */
+ gp_paint_strokeend(p);
+ }
+
+ /* "unlock" frame */
+ if (p->gpf)
+ p->gpf->flag &= ~GP_FRAME_PAINT;
+}
+
+/* ------------------------------- */
+
+/* Helper callback for drawing the cursor itself */
+static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
+{
+ tGPsdata *p = (tGPsdata *)p_ptr;
+
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ GPUVertFormat *format = immVertexFormat();
+ const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ immUniformColor4ub(255, 100, 100, 20);
+ imm_draw_circle_fill_2d(shdr_pos, x, y, p->radius, 40);
+
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniform1f("dash_width", 12.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ imm_draw_circle_wire_2d(shdr_pos, x, y, p->radius,
+ /* XXX Dashed shader gives bad results with sets of small segments currently,
+ * temp hack around the issue. :( */
+ max_ii(8, p->radius / 2)); /* was fixed 40 */
+
+ immUnbindProgram();
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
+ }
+}
+
+/* Turn brush cursor in 3D view on/off */
+static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable)
+{
+ if (p->erasercursor && !enable) {
+ /* clear cursor */
+ WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
+ p->erasercursor = NULL;
+ }
+ else if (enable && !p->erasercursor) {
+ /* enable cursor */
+ p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ NULL, /* XXX */
+ gpencil_draw_eraser, p);
+ }
+}
+
+/* Check if tablet eraser is being used (when processing events) */
+static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
+{
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+ return (wmtab->Active == EVT_TABLET_ERASER);
+ }
+
+ return false;
+}
+
+/* ------------------------------- */
+
+static void gpencil_draw_exit(bContext *C, wmOperator *op)
+{
+ tGPsdata *p = op->customdata;
+
+ /* clear undo stack */
+ gpencil_undo_finish();
+
+ /* restore cursor to indicate end of drawing */
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ /* don't assume that operator data exists at all */
+ if (p) {
+ /* check size of buffer before cleanup, to determine if anything happened here */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ /* turn off radial brush cursor */
+ gpencil_draw_toggle_eraser_cursor(C, p, false);
+ }
+
+ /* always store the new eraser size to be used again next time
+ * NOTE: Do this even when not in eraser mode, as eraser may
+ * have been toggled at some point.
+ */
+ U.gp_eraser = p->radius;
+
+ /* cleanup */
+ gp_paint_cleanup(p);
+ gp_session_cleanup(p);
+ gp_session_free(p);
+ }
+
+ op->customdata = NULL;
+}
+
+static void gpencil_draw_cancel(bContext *C, wmOperator *op)
+{
+ /* this is just a wrapper around exit() */
+ gpencil_draw_exit(C, op);
+}
+
+/* ------------------------------- */
+
+
+static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGPsdata *p;
+ eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
+
+ /* check context */
+ p = op->customdata = gp_session_initpaint(C);
+ if ((p == NULL) || (p->status == GP_STATUS_ERROR)) {
+ /* something wasn't set correctly in context */
+ gpencil_draw_exit(C, op);
+ return 0;
+ }
+
+ /* init painting data */
+ gp_paint_initstroke(p, paintmode, CTX_data_depsgraph(C));
+ if (p->status == GP_STATUS_ERROR) {
+ gpencil_draw_exit(C, op);
+ return 0;
+ }
+
+ if (event != NULL) {
+ p->keymodifier = event->keymodifier;
+ }
+ else {
+ p->keymodifier = -1;
+ }
+
+ /* everything is now setup ok */
+ return 1;
+}
+
+
+/* ------------------------------- */
+
+/* ensure that the correct cursor icon is set */
+static void gpencil_draw_cursor_set(tGPsdata *p)
+{
+ if (p->paintmode == GP_PAINTMODE_ERASER)
+ WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ else
+ WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
+}
+
+/* update UI indicators of status, including cursor and header prints */
+static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
+{
+ /* header prints */
+ switch (p->status) {
+ case GP_STATUS_PAINTING:
+ switch (p->paintmode) {
+ case GP_PAINTMODE_DRAW_POLY:
+ /* Provide usage tips, since this is modal, and unintuitive without hints */
+ ED_workspace_status_text(C, IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+ default:
+ /* Do nothing - the others are self explanatory, exit quickly once the mouse is released
+ * Showing any text would just be annoying as it would flicker.
+ */
+ break;
+ }
+ break;
+
+ case GP_STATUS_IDLING:
+ /* print status info */
+ switch (p->paintmode) {
+ case GP_PAINTMODE_ERASER:
+ ED_workspace_status_text(C, IFACE_("Annotation Eraser: Hold and drag LMB or RMB to erase | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+ case GP_PAINTMODE_DRAW_STRAIGHT:
+ ED_workspace_status_text(C, IFACE_("Annotation Line Draw: Hold and drag LMB to draw | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+ case GP_PAINTMODE_DRAW:
+ ED_workspace_status_text(C, IFACE_("Annotation Freehand Draw: Hold and drag LMB to draw | "
+ "E/ESC/Enter to end (or click outside this area)"));
+ break;
+ case GP_PAINTMODE_DRAW_POLY:
+ ED_workspace_status_text(C, IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+
+ default: /* unhandled future cases */
+ ED_workspace_status_text(C, IFACE_("Annotation Session: ESC/Enter to end (or click outside this area)"));
+ break;
+ }
+ break;
+
+ case GP_STATUS_ERROR:
+ case GP_STATUS_DONE:
+ /* clear status string */
+ ED_workspace_status_text(C, NULL);
+ break;
+ }
+}
+
+/* ------------------------------- */
+
+/* create a new stroke point at the point indicated by the painting context */
+static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph)
+{
+ /* handle drawing/erasing -> test for erasing first */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ /* do 'live' erasing now */
+ gp_stroke_doeraser(p);
+
+ /* store used values */
+ p->mvalo[0] = p->mval[0];
+ p->mvalo[1] = p->mval[1];
+ 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)) {
+ /* 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 */
+ p->mvalo[0] = p->mval[0];
+ p->mvalo[1] = p->mval[1];
+ p->opressure = p->pressure;
+ p->ocurtime = p->curtime;
+ }
+}
+
+/* handle draw event */
+static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsgraph *depsgraph)
+{
+ tGPsdata *p = op->customdata;
+ PointerRNA itemptr;
+ float mousef[2];
+ int tablet = 0;
+
+ /* convert from window-space to area-space mouse coordinates
+ * NOTE: float to ints conversions, +1 factor is probably used to ensure a bit more accurate rounding...
+ */
+ p->mval[0] = event->mval[0] + 1;
+ p->mval[1] = event->mval[1] + 1;
+
+ /* verify key status for straight lines */
+ if ((event->ctrl > 0) || (event->alt > 0)) {
+ if (p->straight[0] == 0) {
+ int dx = abs(p->mval[0] - p->mvalo[0]);
+ int dy = abs(p->mval[1] - p->mvalo[1]);
+ if ((dx > 0) || (dy > 0)) {
+ /* check mouse direction to replace the other coordinate with previous values */
+ if (dx >= dy) {
+ /* horizontal */
+ p->straight[0] = 1;
+ p->straight[1] = p->mval[1]; /* save y */
+ }
+ else {
+ /* vertical */
+ p->straight[0] = 2;
+ p->straight[1] = p->mval[0]; /* save x */
+ }
+ }
+ }
+ }
+ else {
+ p->straight[0] = 0;
+ }
+
+ p->curtime = PIL_check_seconds_timer();
+
+ /* handle pressure sensitivity (which is supplied by tablets) */
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+
+ tablet = (wmtab->Active != EVT_TABLET_NONE);
+ p->pressure = wmtab->Pressure;
+
+ /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
+ * The pen has to float over the tablet surface, resulting in
+ * zero pressure (T47101). Ignore pressure values if floating
+ * (i.e. "effectively zero" pressure), and only when the "active"
+ * end is the stylus (i.e. the default when not eraser)
+ */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
+ p->pressure = 1.0f;
+ }
+ }
+ }
+ else {
+ /* No tablet data -> No pressure info is available */
+ p->pressure = 1.0f;
+ }
+
+ /* special exception for start of strokes (i.e. maybe for just a dot) */
+ if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
+ p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
+
+ p->mvalo[0] = p->mval[0];
+ p->mvalo[1] = p->mval[1];
+ p->opressure = p->pressure;
+ p->inittime = p->ocurtime = p->curtime;
+ p->straight[0] = 0;
+ p->straight[1] = 0;
+
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets, then we just skip first touch...
+ */
+ if (tablet && (p->pressure >= 0.99f))
+ return;
+ }
+
+ /* check if alt key is pressed and limit to straight lines */
+ if (p->straight[0] != 0) {
+ if (p->straight[0] == 1) {
+ /* horizontal */
+ p->mval[1] = p->straight[1]; /* replace y */
+ }
+ else {
+ /* vertical */
+ p->mval[0] = p->straight[1]; /* replace x */
+ }
+ }
+
+ /* fill in stroke data (not actually used directly by gpencil_draw_apply) */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+
+ mousef[0] = p->mval[0];
+ mousef[1] = p->mval[1];
+ RNA_float_set_array(&itemptr, "mouse", mousef);
+ RNA_float_set(&itemptr, "pressure", p->pressure);
+ RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN) != 0);
+
+ RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
+
+ /* apply the current latest drawing point */
+ gpencil_draw_apply(op, p, depsgraph);
+
+ /* force refresh */
+ ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */
+}
+
+/* ------------------------------- */
+
+/* operator 'redo' (i.e. after changing some properties, but also for repeat last) */
+static int gpencil_draw_exec(bContext *C, wmOperator *op)
+{
+ tGPsdata *p = NULL;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ /* printf("GPencil - Starting Re-Drawing\n"); */
+
+ /* try to initialize context data needed while drawing */
+ if (!gpencil_draw_init(C, op, NULL)) {
+ if (op->customdata) MEM_freeN(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] = (int)mousef[0];
+ p->mval[1] = (int)mousef[1];
+ p->pressure = RNA_float_get(&itemptr, "pressure");
+ p->curtime = (double)RNA_float_get(&itemptr, "time") + p->inittime;
+
+ if (RNA_boolean_get(&itemptr, "is_start")) {
+ /* if first-run flag isn't set already (i.e. not true first stroke),
+ * then we must terminate the previous one first before continuing
+ */
+ if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
+ /* TODO: both of these ops can set error-status, but we probably don't need to worry */
+ gp_paint_strokeend(p);
+ gp_paint_initstroke(p, p->paintmode, depsgraph);
+ }
+ }
+
+ /* if first run, set previous data too */
+ if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
+ p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
+
+ p->mvalo[0] = p->mval[0];
+ p->mvalo[1] = p->mval[1];
+ p->opressure = p->pressure;
+ p->ocurtime = p->curtime;
+ }
+
+ /* apply this data as necessary now (as per usual) */
+ gpencil_draw_apply(op, p, depsgraph);
+ }
+ RNA_END;
+
+ /* printf("\tGP - done\n"); */
+
+ /* cleanup */
+ gpencil_draw_exit(C, op);
+
+ /* refreshes */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* done */
+ return OPERATOR_FINISHED;
+}
+
+/* ------------------------------- */
+
+/* start of interactive drawing part of operator */
+static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ tGPsdata *p = NULL;
+
+ /* GPXX Need a better solution */
+ if ((ob != NULL) && (ob->type == OB_GPENCIL)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot draw annotation with a Grease Pencil object active");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (G.debug & G_DEBUG)
+ printf("GPencil - Starting Drawing\n");
+
+ /* try to initialize context data needed while drawing */
+ if (!gpencil_draw_init(C, op, event)) {
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ if (G.debug & G_DEBUG)
+ printf("\tGP - no valid data\n");
+ return OPERATOR_CANCELLED;
+ }
+ else
+ p = op->customdata;
+
+ /* TODO: set any additional settings that we can take from the events?
+ * TODO? if tablet is erasing, force eraser to be on? */
+
+ /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
+
+ /* if eraser is on, draw radial aid */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ gpencil_draw_toggle_eraser_cursor(C, p, true);
+ }
+ /* 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(op, event, CTX_data_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;
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ /* add a modal handler for this operator, so that we can then draw continuous strokes */
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
+static bool gpencil_area_exists(bContext *C, ScrArea *sa_test)
+{
+ bScreen *sc = CTX_wm_screen(C);
+ return (BLI_findindex(&sc->areabase, sa_test) != -1);
+}
+
+static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
+{
+ tGPsdata *p = op->customdata;
+
+ /* we must check that we're still within the area that we're set up to work from
+ * otherwise we could crash (see bug #20586)
+ */
+ if (CTX_wm_area(C) != p->sa) {
+ printf("\t\t\tGP - wrong area execution abort!\n");
+ 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, p))
+ gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C));
+
+ if (p->status != GP_STATUS_ERROR) {
+ p->status = GP_STATUS_PAINTING;
+ op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+ }
+
+ return op->customdata;
+}
+
+static void gpencil_stroke_end(wmOperator *op)
+{
+ tGPsdata *p = op->customdata;
+
+ gp_paint_cleanup(p);
+
+ gpencil_undo_push(p->gpd);
+
+ gp_session_cleanup(p);
+
+ p->status = GP_STATUS_IDLING;
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+
+ p->gpd = NULL;
+ p->gpl = NULL;
+ p->gpf = NULL;
+}
+
+/* events handling during interactive drawing part of operator */
+static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGPsdata *p = op->customdata;
+ int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through to support MMB view nav, etc. */
+
+ /* if (event->type == NDOF_MOTION)
+ * return OPERATOR_PASS_THROUGH;
+ * -------------------------------
+ * [mce] Not quite what I was looking
+ * for, but a good start! GP continues to
+ * draw on the screen while the 3D mouse
+ * moves the viewpoint. Problem is that
+ * the stroke is converted to 3D only after
+ * it is finished. This approach should work
+ * better in tools that immediately apply
+ * in 3D space.
+ */
+
+ if (p->status == GP_STATUS_IDLING) {
+ ARegion *ar = CTX_wm_region(C);
+ p->ar = ar;
+ }
+
+ /* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */
+ if (ISKEYBOARD(event->type)) {
+ if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY, ZKEY)) {
+ /* allow some keys:
+ * - for frame changing [#33412]
+ * - for undo (during sketching sessions)
+ */
+ }
+ else if (ELEM(event->type, PAD0, PAD1, PAD2, PAD3, PAD4, PAD5, PAD6, PAD7, PAD8, PAD9)) {
+ /* allow numpad keys so that camera/view manipulations can still take place
+ * - PAD0 in particular is really important for Grease Pencil drawing,
+ * as animators may be working "to camera", so having this working
+ * is essential for ensuring that they can quickly return to that view
+ */
+ }
+ else if ((event->type == BKEY) && (event->val == KM_RELEASE)) {
+ /* Add Blank Frame
+ * - Since this operator is non-modal, we can just call it here, and keep going...
+ * - This operator is especially useful when animating
+ */
+ WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL);
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ }
+
+ //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 [#32647]
+ */
+ if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) {
+ /* exit() ends the current stroke before cleaning up */
+ /* printf("\t\tGP - end of paint op + end of stroke\n"); */
+ 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)
+ * (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"); */
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+ }
+ else if (event->val == KM_PRESS) {
+ bool in_bounds = false;
+
+ /* Check if we're outside the bounds of the active region
+ * NOTE: An exception here is that if launched from the toolbar,
+ * whatever region we're now in should become the new region
+ */
+ if ((p->ar) && (p->ar->regiontype == RGN_TYPE_TOOLS)) {
+ /* Change to whatever region is now under the mouse */
+ ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
+
+ if (G.debug & G_DEBUG) {
+ printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
+ current_region, p->ar, event->x, event->y,
+ p->sa->totrct.xmin, p->sa->totrct.ymin, p->sa->totrct.xmax, p->sa->totrct.ymax);
+ }
+
+ if (current_region) {
+ /* Assume that since we found the cursor in here, it is in bounds
+ * and that this should be the region that we begin drawing in
+ */
+ p->ar = current_region;
+ in_bounds = true;
+ }
+ else {
+ /* Out of bounds, or invalid in some other way */
+ p->status = GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
+
+ if (G.debug & G_DEBUG)
+ printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__);
+ }
+ }
+ else if (p->ar) {
+ rcti region_rect;
+
+ /* Perform bounds check using */
+ ED_region_visible_rect(p->ar, &region_rect);
+ in_bounds = BLI_rcti_isect_pt_v(&region_rect, event->mval);
+ }
+ else {
+ /* No region */
+ p->status = GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
+
+ if (G.debug & G_DEBUG)
+ printf("%s: No active region found in GP Paint session data\n", __func__);
+ }
+
+ if (in_bounds) {
+ /* Switch paintmode (temporarily if need be) based on which button was used
+ * NOTE: This is to make it more convenient to erase strokes when using drawing sessions
+ */
+ if ((event->type == RIGHTMOUSE) || gpencil_is_tablet_eraser_active(event)) {
+ /* turn on eraser */
+ p->paintmode = GP_PAINTMODE_ERASER;
+ }
+ else if (event->type == LEFTMOUSE) {
+ /* restore drawmode to default */
+ p->paintmode = RNA_enum_get(op->ptr, "mode");
+ }
+
+ gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
+
+ /* not painting, so start stroke (this should be mouse-button down) */
+ p = gpencil_stroke_begin(C, op);
+
+ if (p->status == GP_STATUS_ERROR) {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ else if (p->status != GP_STATUS_ERROR) {
+ /* User clicked outside bounds of window while idling, so exit paintmode
+ * NOTE: Don't enter this case if an error occurred while finding the
+ * region (as above)
+ */
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+ }
+ else if (event->val == KM_RELEASE) {
+ p->status = GP_STATUS_IDLING;
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+ }
+
+ /* handle mode-specific events */
+ if (p->status == GP_STATUS_PAINTING) {
+ /* 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"); */
+ gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C));
+
+ /* finish painting operation if anything went wrong just now */
+ if (p->status == GP_STATUS_ERROR) {
+ printf("\t\t\t\tGP - add error done!\n");
+ estate = OPERATOR_CANCELLED;
+ }
+ 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"); */
+ switch (event->type) {
+ case WHEELDOWNMOUSE: /* larger */
+ case PADPLUSKEY:
+ p->radius += 5;
+ break;
+
+ case WHEELUPMOUSE: /* smaller */
+ case PADMINUS:
+ p->radius -= 5;
+
+ if (p->radius <= 0)
+ p->radius = 1;
+ break;
+ }
+
+ /* force refresh */
+ ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */
+
+ /* event handled, so just tag as running modal */
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ /* there shouldn't be any other events, but just in case there are, let's swallow them
+ * (i.e. to prevent problems with undo)
+ */
+ else {
+ /* swallow event to save ourselves trouble */
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ }
+
+ /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
+ if (0 == gpencil_area_exists(C, p->sa))
+ estate = OPERATOR_CANCELLED;
+ 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 */
+ switch (estate) {
+ case OPERATOR_FINISHED:
+ /* one last flush before we're done */
+ gpencil_draw_exit(C, op);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ break;
+
+ case OPERATOR_CANCELLED:
+ gpencil_draw_exit(C, op);
+ break;
+
+ 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;
+ }
+
+ /* return status code */
+ return estate;
+}
+
+/* ------------------------------- */
+
+static const EnumPropertyItem prop_gpencil_drawmodes[] = {
+ {GP_PAINTMODE_DRAW, "DRAW", 0, "Draw Freehand", "Draw freehand stroke(s)"},
+ {GP_PAINTMODE_DRAW_STRAIGHT, "DRAW_STRAIGHT", 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 Annotation strokes"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+void GPENCIL_OT_annotate(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Annotation Draw";
+ ot->idname = "GPENCIL_OT_annotate";
+ ot->description = "Make annotations on the active data";
+
+ /* api callbacks */
+ ot->exec = gpencil_draw_exec;
+ ot->invoke = gpencil_draw_invoke;
+ ot->modal = gpencil_draw_modal;
+ ot->cancel = gpencil_draw_cancel;
+ ot->poll = gpencil_draw_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* settings for drawing */
+ ot->prop = RNA_def_enum(ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
+
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ /* NOTE: wait for input is enabled by default, so that all UI code can work properly without needing users to know about this */
+ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Wait for first click instead of painting immediately");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 29b24886017..5c56877cbe6 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -46,6 +46,7 @@
#include "BLF_api.h"
#include "BLT_translation.h"
+#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -55,8 +56,13 @@
#include "DNA_object_types.h"
#include "BKE_context.h"
+#include "BKE_brush.h"
#include "BKE_global.h"
+#include "BKE_paint.h"
#include "BKE_gpencil.h"
+#include "BKE_image.h"
+
+#include "DEG_depsgraph.h"
#include "WM_api.h"
@@ -74,6 +80,10 @@
#include "UI_interface_icons.h"
#include "UI_resources.h"
+#include "IMB_imbuf_types.h"
+
+#include "gpencil_intern.h"
+
/* ************************************************** */
/* GREASE PENCIL DRAWING */
@@ -88,8 +98,7 @@ typedef enum eDrawStrokeFlags {
GP_DRAWDATA_NO_XRAY = (1 << 5), /* don't draw xray in 3D view (which is default) */
GP_DRAWDATA_NO_ONIONS = (1 << 6), /* no onionskins should be drawn (for animation playback) */
GP_DRAWDATA_VOLUMETRIC = (1 << 7), /* draw strokes as "volumetric" circular billboards */
- GP_DRAWDATA_FILL = (1 << 8), /* fill insides/bounded-regions of strokes */
- GP_DRAWDATA_HQ_FILL = (1 << 9) /* Use high quality fill */
+ GP_DRAWDATA_FILL = (1 << 8) /* fill insides/bounded-regions of strokes */
} eDrawStrokeFlags;
@@ -100,12 +109,12 @@ typedef enum eDrawStrokeFlags {
#endif
/* conversion utility (float --> normalized unsigned byte) */
-#define F2UB(x) (unsigned char)(255.0f * x)
+#define F2UB(x) (uchar)(255.0f * x)
/* ----- Tool Buffer Drawing ------ */
/* helper functions to set color of buffer point */
-static void gp_set_tpoint_varying_color(const tGPspoint *pt, const float ink[4], unsigned attrib_id)
+static void gp_set_tpoint_varying_color(const tGPspoint *pt, const float ink[4], uint attrib_id)
{
float alpha = ink[3] * pt->strength;
CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
@@ -119,7 +128,7 @@ static void gp_set_point_uniform_color(const bGPDspoint *pt, const float ink[4])
immUniformColor3fvAlpha(ink, alpha);
}
-static void gp_set_point_varying_color(const bGPDspoint *pt, const float ink[4], unsigned attrib_id)
+static void gp_set_point_varying_color(const bGPDspoint *pt, const float ink[4], uint attrib_id)
{
float alpha = ink[3] * pt->strength;
CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
@@ -134,7 +143,7 @@ static void gp_draw_stroke_buffer_fill(const tGPspoint *points, int totpoints, f
}
int tot_triangles = totpoints - 2;
/* allocate memory for temporary areas */
- unsigned int(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, "GP Stroke buffer temp triangulation");
+ uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, "GP Stroke buffer temp triangulation");
float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, "GP Stroke buffer temp 2d points");
/* Convert points to array and triangulate
@@ -146,7 +155,7 @@ static void gp_draw_stroke_buffer_fill(const tGPspoint *points, int totpoints, f
points2d[i][0] = pt->x;
points2d[i][1] = pt->y;
}
- BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)totpoints, 0, (unsigned int(*)[3])tmp_triangles);
+ BLI_polyfill_calc((const float(*)[2])points2d, (uint)totpoints, 0, (uint(*)[3])tmp_triangles);
/* draw triangulation data */
if (tot_triangles > 0) {
@@ -253,7 +262,7 @@ static void gp_draw_stroke_buffer(const tGPspoint *points, int totpoints, short
if (i != 0) {
gp_set_tpoint_varying_color(pt - 1, ink, color);
immVertex2iv(pos, &(pt - 1)->x);
- ++draw_points;
+ draw_points++;
}
oldpressure = pt->pressure; /* reset our threshold */
@@ -262,7 +271,7 @@ static void gp_draw_stroke_buffer(const tGPspoint *points, int totpoints, short
/* now the point we want */
gp_set_tpoint_varying_color(pt, ink, color);
immVertex2iv(pos, &pt->x);
- ++draw_points;
+ draw_points++;
}
/* need to have 2 points to avoid immEnd assert error */
if (draw_points < 2) {
@@ -402,6 +411,50 @@ static void gp_draw_stroke_volumetric_3d(
/* --------------- 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, 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];
+ }
+}
/* Get points of stroke always flat to view not affected by camera view or view position */
static void gp_stroke_2d_flat(const bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction)
@@ -447,7 +500,6 @@ static void gp_stroke_2d_flat(const bGPDspoint *points, int totpoints, float(*po
*r_direction = (int)locy[2];
}
-
/* 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)
{
@@ -455,14 +507,23 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
/* allocate memory for temporary areas */
gps->tot_triangles = gps->totpoints - 2;
- unsigned int (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation");
+ 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 */
gp_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
- BLI_polyfill_calc(points2d, (unsigned int)gps->totpoints, direction, tmp_triangles);
+ 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;
@@ -476,7 +537,12 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
}
for (int i = 0; i < gps->tot_triangles; i++) {
- memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3]));
+ 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 {
@@ -493,73 +559,128 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
}
/* clear memory */
- if (tmp_triangles) MEM_freeN(tmp_triangles);
- if (points2d) MEM_freeN(points2d);
+ MEM_SAFE_FREE(tmp_triangles);
+ MEM_SAFE_FREE(points2d);
+ MEM_SAFE_FREE(uv);
}
-
-/* draw fills for shapes */
-static void gp_draw_stroke_fill(
- bGPdata *gpd, bGPDstroke *gps,
- int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float color[4])
+/* 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,
+ int offsx, int offsy, int winx, int winy, const float diff_mat[4][4])
{
float fpt[3];
+ float co[2];
- BLI_assert(gps->totpoints >= 3);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* if 2d, need conversion */
+ if (!flag & GP_STROKE_3DSPACE) {
+ gp_calc_2d_stroke_fxy(fpt, flag, offsx, offsy, winx, winy, co);
+ copy_v2_v2(fpt, co);
+ fpt[2] = 0.0f; /* 2d always is z=0.0f */
+ }
- bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+ immAttrib2f(texcoord, uv[0], uv[1]); /* texture coordinates */
+ immVertex3fv(pos, fpt); /* position */
+}
- /* Triangulation fill if high quality flag is enabled */
- if (palcolor->flag & PC_COLOR_HQ_FILL) {
- /* Calculate triangles cache for filling area (must be done only after changes) */
- if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
- gp_triangulate_stroke_fill(gps);
- }
- BLI_assert(gps->tot_triangles >= 1);
+#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;
- uint pos;
- if (gps->flag & GP_STROKE_3DSPACE) {
- pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- }
- else {
- pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- }
+ iuser.ok = true;
- immUniformColor4fv(color);
+ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
- /* 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 */
+ if (ibuf == NULL || ibuf->rect == NULL) {
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ return (int)GL_INVALID_OPERATION;
+ }
- bGPDtriangle *stroke_triangle = gps->triangles;
- bGPDspoint *pt;
+ GPU_create_gl_tex(bind, ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, GL_TEXTURE_2D,
+ false, false, image);
- if (gps->flag & GP_STROKE_3DSPACE) {
- for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
- for (int j = 0; j < 3; j++) {
- pt = &gps->points[stroke_triangle->verts[j]];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- immVertex3fv(pos, fpt);
- }
- }
- }
- else {
- for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
- for (int j = 0; j < 3; j++) {
- float co[2];
- pt = &gps->points[stroke_triangle->verts[j]];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
- immVertex3fv(pos, fpt);
- }
- }
- }
+ 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);
- immEnd();
- immUnbindProgram();
+ return error;
+}
+#endif
+
+/* draw fills for shapes */
+static void gp_draw_stroke_fill(
+ bGPdata *gpd, bGPDstroke *gps,
+ int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float color[4])
+{
+ BLI_assert(gps->totpoints >= 3);
+ Material *ma = gpd->mat[gps->mat_nr];
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+
+ /* Calculate triangles cache for filling area (must be done only after changes) */
+ if ((gps->flag & GP_STROKE_RECALC_CACHES) || (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);
+ immBindBuiltinProgram(GPU_SHADER_GPENCIL_FILL);
+
+ immUniformColor4fv(color);
+ immUniform4fv("color2", gp_style->mix_rgba);
+ 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_COLOR_TEX_MIX ? 1 : 0);
+ immUniform1i("t_flip", gp_style->flag & GP_STYLE_COLOR_FLIP_FILL ? 1 : 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
+ /* 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 */
+
+ const bGPDtriangle *stroke_triangle = gps->triangles;
+ 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,
+ offsx, offsy, winx, winy, diff_mat);
+ }
+ }
+
+ immEnd();
+ immUnbindProgram();
}
/* ----- Existing Strokes Drawing (3D and Point) ------ */
@@ -601,87 +722,81 @@ static void gp_draw_stroke_point(
immUnbindProgram();
}
-/* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
-static void gp_draw_stroke_3d(const bGPDspoint *points, int totpoints, short thickness, bool UNUSED(debug),
- short UNUSED(sflag), const float diff_mat[4][4], const float ink[4], bool cyclic)
+/* draw a given stroke in 3d (i.e. in 3d-space) */
+static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4], bool cyclic)
{
+ bGPDspoint *points = tgpw->gps->points;
+ int totpoints = tgpw->gps->totpoints;
+
+ const float viewport[2] = { (float)tgpw->winx, (float)tgpw->winy };
float curpressure = points[0].pressure;
float fpt[3];
- float cyclic_fpt[3];
- int draw_points = 0;
-
- /* if cyclic needs one vertex more */
- int cyclic_add = 0;
- if (cyclic) {
- ++cyclic_add;
- }
+ /* if cyclic needs more vertex */
+ int cyclic_add = (cyclic) ? 1 : 0;
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint thickattrib = GPU_vertformat_attr_add(format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_GPENCIL_STROKE);
+ immUniform2fv("Viewport", viewport);
+ immUniform1f("pixsize", tgpw->rv3d->pixsize);
+ immUniform1f("pixelsize", U.pixelsize);
+ float obj_scale = (tgpw->ob->size[0] + tgpw->ob->size[1] + tgpw->ob->size[2]) / 3.0f;
- /* TODO: implement this with a geometry shader to draw one continuous tapered stroke */
+ immUniform1f("objscale", obj_scale);
+ int keep_size = (int)((tgpw->gpd) && (tgpw->gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
+ immUniform1i("keep_size", keep_size);
+ immUniform1i("pixfactor", tgpw->gpd->pixfactor);
+ immUniform1i("xraymode", tgpw->gpd->xray_mode);
/* draw stroke curve */
GPU_line_width(max_ff(curpressure * thickness, 1.0f));
- immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
+ immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, totpoints + cyclic_add + 2);
const bGPDspoint *pt = points;
- for (int i = 0; i < totpoints; i++, pt++) {
- gp_set_point_varying_color(pt, ink, color);
- /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
- * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
- * Note: we want more visible levels of pressures when thickness is bigger.
- */
- if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) {
- /* if the pressure changes before get at least 2 vertices, need to repeat last point to avoid assert in immEnd() */
- if (draw_points < 2) {
- const bGPDspoint *pt2 = pt - 1;
- mul_v3_m4v3(fpt, diff_mat, &pt2->x);
- immVertex3fv(pos, fpt);
+ for (int i = 0; i < totpoints; i++, pt++) {
+ /* first point for adjacency (not drawn) */
+ if (i == 0) {
+ gp_set_point_varying_color(points, ink, color);
+ immAttrib1f(thickattrib, max_ff(curpressure * thickness, 1.0f));
+ if ((cyclic) && (totpoints > 2)) {
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 1)->x);
}
- immEnd();
- draw_points = 0;
-
- curpressure = pt->pressure;
- GPU_line_width(max_ff(curpressure * thickness, 1.0f));
- immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1 + cyclic_add);
-
- /* need to roll-back one point to ensure that there are no gaps in the stroke */
- if (i != 0) {
- const bGPDspoint *pt2 = pt - 1;
- mul_v3_m4v3(fpt, diff_mat, &pt2->x);
- gp_set_point_varying_color(pt2, ink, color);
- immVertex3fv(pos, fpt);
- ++draw_points;
+ else {
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x);
}
+ mul_v3_fl(fpt, -1.0f);
+ immVertex3fv(pos, fpt);
}
-
- /* now the point we want */
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* set point */
+ gp_set_point_varying_color(pt, ink, color);
+ immAttrib1f(thickattrib, max_ff(curpressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &pt->x);
immVertex3fv(pos, fpt);
- ++draw_points;
- if (cyclic && i == 0) {
- /* save first point to use in cyclic */
- copy_v3_v3(cyclic_fpt, fpt);
- }
+ curpressure = pt->pressure;
}
- if (cyclic) {
+ if (cyclic && totpoints > 2) {
/* draw line to first point to complete the cycle */
- immVertex3fv(pos, cyclic_fpt);
- ++draw_points;
- }
+ immAttrib1f(thickattrib, max_ff(points->pressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &points->x);
+ immVertex3fv(pos, fpt);
- /* if less of two points, need to repeat last point to avoid assert in immEnd() */
- if (draw_points < 2) {
- const bGPDspoint *pt2 = pt - 1;
- mul_v3_m4v3(fpt, diff_mat, &pt2->x);
- gp_set_point_varying_color(pt2, ink, color);
+ /* now add adjacency point (not drawn) */
+ immAttrib1f(thickattrib, max_ff((points + 1)->pressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x);
+ immVertex3fv(pos, fpt);
+ }
+ /* last adjacency point (not drawn) */
+ else {
+ gp_set_point_varying_color(points + totpoints - 1, ink, color);
+ immAttrib1f(thickattrib, max_ff(curpressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 2)->x);
+ mul_v3_fl(fpt, -1.0f);
immVertex3fv(pos, fpt);
}
@@ -692,8 +807,9 @@ static void gp_draw_stroke_3d(const bGPDspoint *points, int totpoints, short thi
/* ----- Fancy 2D-Stroke Drawing ------ */
/* draw a given stroke in 2d */
-static void gp_draw_stroke_2d(const bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
- bool UNUSED(debug), int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float ink[4])
+static void gp_draw_stroke_2d(
+ const bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
+ bool UNUSED(debug), int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float ink[4])
{
/* otherwise thickness is twice that of the 3D view */
float thickness = (float)thickness_s * 0.5f;
@@ -900,10 +1016,7 @@ static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
}
/* draw a set of strokes */
-static void gp_draw_strokes(
- bGPdata *gpd, const bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
- bool debug, short lthick, const float opacity, const float tintcolor[4],
- const bool onion, const bool custonion, const float diff_mat[4][4])
+static void gp_draw_strokes(tGPDdraw *tgpw)
{
float tcolor[4];
float tfill[4];
@@ -912,31 +1025,41 @@ static void gp_draw_strokes(
GPU_enable_program_point_size();
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ for (bGPDstroke *gps = tgpw->t_gpf->strokes.first; gps; gps = gps->next) {
/* check if stroke can be drawn */
- if (gp_can_draw_stroke(gps, dflag) == false) {
+ if (gp_can_draw_stroke(gps, tgpw->dflag) == false) {
continue;
}
/* check if the color is visible */
- bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
- if ((palcolor == NULL) ||
- (palcolor->flag & PC_COLOR_HIDE) ||
+ Material *ma = tgpw->gpd->mat[gps->mat_nr];
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+
+ if ((gp_style == NULL) ||
+ (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
/* if onion and ghost flag do not draw*/
- (onion && (palcolor->flag & PC_COLOR_ONIONSKIN)))
+ (tgpw->onion && (gp_style->flag & GP_STYLE_COLOR_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))
+ {
+ continue;
+ }
+
/* calculate thickness */
- sthickness = gps->thickness + lthick;
+ sthickness = gps->thickness + tgpw->lthick;
if (sthickness <= 0) {
continue;
}
/* check which stroke-drawer to use */
- if (dflag & GP_DRAWDATA_ONLY3D) {
- const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
+ if (tgpw->dflag & GP_DRAWDATA_ONLY3D) {
+ const int no_xray = (tgpw->dflag & GP_DRAWDATA_NO_XRAY);
int mask_orig = 0;
if (no_xray) {
@@ -951,57 +1074,64 @@ static void gp_draw_strokes(
/* 3D Fill */
//if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
- if (gps->totpoints >= 3) {
- /* set color using palette, tint color and opacity */
- interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
- tfill[3] = palcolor->fill[3] * opacity;
- if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
+ if ((gps->totpoints >= 3) && (tgpw->disable_fill != 1)) {
+ /* set color using material, tint color and opacity */
+ interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
+ tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity;
+ if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
const float *color;
- if (!onion) {
+ if (!tgpw->onion) {
color = tfill;
}
else {
- if (custonion) {
- color = tintcolor;
+ if (tgpw->custonion) {
+ color = tgpw->tintcolor;
}
else {
- ARRAY_SET_ITEMS(tfill, UNPACK3(palcolor->fill), tintcolor[3]);
+ ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]);
color = tfill;
}
}
- gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat, color);
+ gp_draw_stroke_fill(
+ tgpw->gpd, gps,
+ tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, color);
}
}
/* 3D Stroke */
- /* set color using palette, tint color and opacity */
- if (!onion) {
- interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]);
- tcolor[3] = palcolor->color[3] * opacity;
+ /* set color using material tint color and opacity */
+ if (!tgpw->onion) {
+ interp_v3_v3v3(tcolor, gp_style->stroke_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
+ tcolor[3] = gp_style->stroke_rgba[3] * tgpw->opacity;
copy_v4_v4(ink, tcolor);
}
else {
- if (custonion) {
- copy_v4_v4(ink, tintcolor);
+ if (tgpw->custonion) {
+ copy_v4_v4(ink, tgpw->tintcolor);
}
else {
- ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
+ ARRAY_SET_ITEMS(tcolor, UNPACK3(gp_style->stroke_rgba), tgpw->opacity);
copy_v4_v4(ink, tcolor);
}
}
- if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
+ if (gp_style->mode == GP_STYLE_MODE_DOTS) {
/* volumetric stroke drawing */
- gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink);
+ if (tgpw->disable_fill != 1) {
+ gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink);
+ }
}
else {
/* 3D Lines - OpenGL primitives-based */
if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
- diff_mat, ink);
+ if (tgpw->disable_fill != 1) {
+ gp_draw_stroke_point(gps->points, sthickness, tgpw->dflag, gps->flag,
+ tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy,
+ tgpw->diff_mat, ink);
+ }
}
else {
- gp_draw_stroke_3d(gps->points, gps->totpoints, sthickness, debug, gps->flag,
- diff_mat, ink, gps->flag & GP_STROKE_CYCLIC);
+ tgpw->gps = gps;
+ gp_draw_stroke_3d(tgpw, sthickness, ink, gps->flag & GP_STROKE_CYCLIC);
}
}
if (no_xray) {
@@ -1014,58 +1144,63 @@ static void gp_draw_strokes(
else {
/* 2D - Fill */
if (gps->totpoints >= 3) {
- /* set color using palette, tint color and opacity */
- interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
- tfill[3] = palcolor->fill[3] * opacity;
- if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
+ /* set color using material, tint color and opacity */
+ interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
+ tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity;
+ if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
const float *color;
- if (!onion) {
+ if (!tgpw->onion) {
color = tfill;
}
else {
- if (custonion) {
- color = tintcolor;
+ if (tgpw->custonion) {
+ color = tgpw->tintcolor;
}
else {
- ARRAY_SET_ITEMS(tfill, palcolor->fill[0], palcolor->fill[1], palcolor->fill[2],
- tintcolor[3]);
+ ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]);
color = tfill;
}
}
- gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat, color);
+ gp_draw_stroke_fill(
+ tgpw->gpd, gps,
+ tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, color);
}
}
/* 2D Strokes... */
- /* set color using palette, tint color and opacity */
- if (!onion) {
- interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]);
- tcolor[3] = palcolor->color[3] * opacity;
+ /* set color using material, tint color and opacity */
+ if (!tgpw->onion) {
+ interp_v3_v3v3(tcolor, gp_style->stroke_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
+ tcolor[3] = gp_style->stroke_rgba[3] * tgpw->opacity;
copy_v4_v4(ink, tcolor);
}
else {
- if (custonion) {
- copy_v4_v4(ink, tintcolor);
+ if (tgpw->custonion) {
+ copy_v4_v4(ink, tgpw->tintcolor);
}
else {
- ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
+ ARRAY_SET_ITEMS(tcolor, UNPACK3(gp_style->stroke_rgba), tgpw->opacity);
copy_v4_v4(ink, tcolor);
}
}
- if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
+ if (gp_style->mode == GP_STYLE_MODE_DOTS) {
/* blob/disk-based "volumetric" drawing */
- gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag,
- offsx, offsy, winx, winy, diff_mat, ink);
+ gp_draw_stroke_volumetric_2d(
+ gps->points, gps->totpoints, sthickness, tgpw->dflag, gps->flag,
+ tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, ink);
}
else {
/* normal 2D strokes */
if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
- diff_mat, ink);
+ gp_draw_stroke_point(
+ gps->points, sthickness, tgpw->dflag, gps->flag,
+ tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy,
+ tgpw->diff_mat, ink);
}
else {
- gp_draw_stroke_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, debug,
- offsx, offsy, winx, winy, diff_mat, ink);
+ gp_draw_stroke_2d(
+ gps->points, gps->totpoints, sthickness, tgpw->dflag, gps->flag, false,
+ tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, ink);
}
}
}
@@ -1114,14 +1249,16 @@ static void gp_draw_strokes_edit(
if ((gps->flag & GP_STROKE_SELECT) == 0)
continue;
- /* verify palette color lock */
+ /* verify color lock */
{
- bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
- if (palcolor != NULL) {
- if (palcolor->flag & PC_COLOR_HIDE) {
+ Material *ma = gpd->mat[gps->mat_nr];
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+
+ if (gp_style != NULL) {
+ if (gp_style->flag & GP_STYLE_COLOR_HIDE) {
continue;
}
- if (((lflag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED)) {
+ if (((lflag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_STYLE_COLOR_LOCKED)) {
continue;
}
}
@@ -1143,8 +1280,9 @@ static void gp_draw_strokes_edit(
}
/* for now, we assume that the base color of the points is not too close to the real color */
- /* set color using palette */
- bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+ /* set color using material */
+ Material *ma = gpd->mat[gps->mat_nr];
+ MaterialGPencilStyle *gp_style = ma->gp_style;
float selectColor[4];
UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
@@ -1153,7 +1291,7 @@ static void gp_draw_strokes_edit(
GPUVertFormat *format = immVertexFormat();
uint pos; /* specified later */
uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
if (gps->flag & GP_STROKE_3DSPACE) {
pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
@@ -1189,7 +1327,7 @@ static void gp_draw_strokes_edit(
immAttrib1f(size, vsize);
}
else {
- immAttrib3fv(color, palcolor->color);
+ immAttrib3fv(color, gp_style->stroke_rgba);
immAttrib1f(size, bsize);
}
@@ -1229,98 +1367,75 @@ static void gp_draw_strokes_edit(
/* ----- General Drawing ------ */
-/* draw onion-skinning for a layer */
-static void gp_draw_onionskins(
- bGPdata *gpd, const bGPDlayer *gpl, const bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
- int UNUSED(cfra), int dflag, bool debug, const float diff_mat[4][4])
+
+/* draw interpolate strokes (used only while operator is running) */
+void ED_gp_draw_interpolation(const bContext *C, tGPDinterpolate *tgpi, const int type)
{
- const float default_color[3] = {UNPACK3(U.gpencil_new_layer_col)};
- const float alpha = 1.0f;
+ tGPDdraw tgpw;
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+ tGPDinterpolate_layer *tgpil;
+ Object *obact = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
float color[4];
- /* 1) Draw Previous Frames First */
- if (gpl->flag & GP_LAYER_GHOST_PREVCOL) {
- copy_v3_v3(color, gpl->gcolor_prev);
- }
- else {
- copy_v3_v3(color, default_color);
+ 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);
}
- if (gpl->gstep > 0) {
- /* draw previous frames first */
- for (bGPDframe *gf = gpf->prev; gf; gf = gf->prev) {
- /* check if frame is drawable */
- if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
- /* alpha decreases with distance from curframe index */
- float fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
- color[3] = alpha * fac * 0.66f;
- gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
- true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat);
- }
- else
- break;
- }
- }
- else if (gpl->gstep == 0) {
- /* draw the strokes for the ghost frames (at half of the alpha set by user) */
- if (gpf->prev) {
- color[3] = (alpha / 7);
- gp_draw_strokes(gpd, gpf->prev, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
- true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat);
- }
- }
- else {
- /* don't draw - disabled */
- }
+ tgpw.rv3d = rv3d;
+ tgpw.depsgraph = depsgraph;
+ tgpw.ob = obact;
+ tgpw.gpd = tgpi->gpd;
+ tgpw.offsx = 0;
+ tgpw.offsy = 0;
+ tgpw.winx = tgpi->ar->winx;
+ tgpw.winy = tgpi->ar->winy;
+ tgpw.dflag = dflag;
- /* 2) Now draw next frames */
- if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) {
- copy_v3_v3(color, gpl->gcolor_next);
- }
- else {
- copy_v3_v3(color, default_color);
- }
+ /* turn on alpha-blending */
+ glEnable(GL_BLEND);
+ 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;
- if (gpl->gstep_next > 0) {
- /* now draw next frames */
- for (bGPDframe *gf = gpf->next; gf; gf = gf->next) {
- /* check if frame is drawable */
- if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) {
- /* alpha decreases with distance from curframe index */
- float fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
- color[3] = alpha * fac * 0.66f;
- gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
- true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat);
- }
- else
- break;
- }
- }
- else if (gpl->gstep_next == 0) {
- /* draw the strokes for the ghost frames (at half of the alpha set by user) */
- if (gpf->next) {
- color[3] = (alpha / 4);
- gp_draw_strokes(gpd, gpf->next, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
- true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat);
+ tgpw.lthick = tgpil->gpl->line_change;
+ tgpw.opacity = 1.0;
+ copy_v4_v4(tgpw.tintcolor, color);
+ tgpw.onion = true;
+ tgpw.custonion = true;
+
+ gp_draw_strokes(&tgpw);
}
}
- else {
- /* don't draw - disabled */
- }
+ glDisable(GL_BLEND);
}
/* draw interpolate strokes (used only while operator is running) */
-void ED_gp_draw_interpolation(tGPDinterpolate *tgpi, const int type)
+void ED_gp_draw_primitives(const bContext *C, tGPDprimitive *tgpi, const int type)
{
- tGPDinterpolate_layer *tgpil;
- float diff_mat[4][4];
- float color[4];
+ tGPDdraw tgpw;
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* if idle, do not draw */
+ if (tgpi->flag == 0) {
+ return;
+ }
- int offsx = 0;
- int offsy = 0;
- int winx = tgpi->ar->winx;
- int winy = tgpi->ar->winy;
+ Object *obact = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C); \
+ float color[4];
UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, color);
color[3] = 0.6f;
int dflag = 0;
@@ -1329,32 +1444,71 @@ void ED_gp_draw_interpolation(tGPDinterpolate *tgpi, const int type)
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->ar->winx;
+ tgpw.winy = tgpi->ar->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(tgpil->gpl, diff_mat);
- if (tgpil->interFrame) {
- gp_draw_strokes(tgpi->gpd, tgpil->interFrame, offsx, offsy, winx, winy, dflag, false,
- tgpil->gpl->thickness, 1.0f, color, true, true, diff_mat);
+ /* calculate parent position */
+ ED_gpencil_parent_location(depsgraph, obact, tgpi->gpd, tgpi->gpl, tgpw.diff_mat);
+ if (tgpi->gpf) {
+ tgpw.gps = tgpi->gpf->strokes.first;
+ if (tgpw.gps->totpoints > 0) {
+ tgpw.gpl = tgpi->gpl;
+ tgpw.gpf = tgpi->gpf;
+ tgpw.t_gpf = tgpi->gpf;
+
+ tgpw.lthick = tgpi->gpl->line_change;
+ tgpw.opacity = 1.0;
+ copy_v4_v4(tgpw.tintcolor, color);
+ tgpw.onion = true;
+ tgpw.custonion = true;
+
+ 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);
+}
+
/* loop over gpencil data layers, drawing them */
-static void gp_draw_data_layers(
- const bGPDbrush *brush, float alpha, bGPdata *gpd,
+static void gp_draw_data_layers(RegionView3D *rv3d,
+ const Brush *brush, float alpha, Object *ob, bGPdata *gpd,
int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
float diff_mat[4][4];
+ tGPDdraw tgpw;
+
+ tgpw.rv3d = rv3d;
+ tgpw.depsgraph = NULL; /* XXX: This is not used here */
+ tgpw.ob = ob;
+ tgpw.gpd = gpd;
+ tgpw.gpl = NULL;
+ tgpw.gpf = NULL;
+ tgpw.t_gpf = NULL;
+ tgpw.offsx = offsx;
+ tgpw.offsy = offsy;
+ tgpw.winx = winx;
+ tgpw.winy = winy;
+ tgpw.dflag = dflag;
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* calculate parent position */
- ED_gpencil_parent_location(gpl, diff_mat);
+ ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, diff_mat);
- bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG);
- short lthick = brush->thickness + gpl->thickness;
+ short lthick = brush->size + gpl->line_change;
/* don't draw layer if hidden */
if (gpl->flag & GP_LAYER_HIDE)
@@ -1383,30 +1537,20 @@ static void gp_draw_data_layers(
/* volumetric strokes... */
GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC);
- /* HQ fills... */
- GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_HQ_FILL), GP_DRAWDATA_HQ_FILL);
-
#undef GP_DRAWFLAG_APPLY
- /* Draw 'onionskins' (frame left + right)
- * - It is only possible to show these if the option is enabled
- * - The "no onions" flag prevents ghosts from appearing during animation playback/scrubbing
- * and in renders
- * - The per-layer "always show" flag however overrides the playback/render restriction,
- * allowing artists to selectively turn onionskins on/off during playback
- */
- if ((gpl->flag & GP_LAYER_ONIONSKIN) &&
- ((dflag & GP_DRAWDATA_NO_ONIONS) == 0 || (gpl->flag & GP_LAYER_GHOST_ALWAYS)))
- {
- /* Drawing method - only immediately surrounding (gstep = 0),
- * or within a frame range on either side (gstep > 0)
- */
- gp_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, diff_mat);
- }
+ tgpw.gpl = gpl;
+ tgpw.gpf = gpf;
+ tgpw.t_gpf = gpf; // XXX?
+ tgpw.lthick = gpl->line_change;
+ tgpw.opacity = gpl->opacity;
+ copy_v4_v4(tgpw.tintcolor, gpl->tintcolor);
+ tgpw.onion = false;
+ tgpw.custonion = false;
+ copy_m4_m4(tgpw.diff_mat, diff_mat);
/* draw the strokes already in active frame */
- gp_draw_strokes(gpd, gpf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness,
- gpl->opacity, gpl->tintcolor, false, false, diff_mat);
+ gp_draw_strokes(&tgpw);
/* Draw verts of selected strokes
* - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
@@ -1435,19 +1579,25 @@ static void gp_draw_data_layers(
* It should also be noted that sbuffer contains temporary point types
* i.e. tGPspoints NOT bGPDspoints
*/
- if (gpd->sflag & PC_COLOR_VOLUMETRIC) {
- gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick,
- dflag, gpd->scolor);
+ if (gpd->runtime.mode == GP_STYLE_MODE_DOTS) {
+ gp_draw_stroke_volumetric_buffer(
+ gpd->runtime.sbuffer,
+ gpd->runtime.sbuffer_size, lthick,
+ dflag, gpd->runtime.scolor);
}
else {
- gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor, gpd->sfill);
+ gp_draw_stroke_buffer(
+ gpd->runtime.sbuffer,
+ gpd->runtime.sbuffer_size, lthick,
+ dflag, gpd->runtime.sbuffer_sflag,
+ gpd->runtime.scolor, gpd->runtime.sfill);
}
}
}
}
/* draw a short status message in the top-right corner */
-static void gp_draw_status_text(const bGPdata *gpd, ARegion *ar)
+static void UNUSED_FUNCTION(gp_draw_status_text)(const bGPdata *gpd, ARegion *ar)
{
rcti rect;
@@ -1493,8 +1643,8 @@ static void gp_draw_status_text(const bGPdata *gpd, ARegion *ar)
}
/* draw grease-pencil datablock */
-static void gp_draw_data(
- const bGPDbrush *brush, float alpha, bGPdata *gpd,
+static void gp_draw_data(RegionView3D *rv3d,
+ const Brush *brush, float alpha, Object *ob, bGPdata *gpd,
int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
/* turn on smooth lines (i.e. anti-aliasing) */
@@ -1510,7 +1660,7 @@ static void gp_draw_data(
GPU_blend(true);
/* draw! */
- gp_draw_data_layers(brush, alpha, gpd, offsx, offsy, winx, winy, cfra, dflag);
+ gp_draw_data_layers(rv3d, brush, alpha, ob, gpd, offsx, offsy, winx, winy, cfra, dflag);
/* turn off alpha blending, then smooth lines */
GPU_blend(false); // alpha blending
@@ -1519,33 +1669,22 @@ static void gp_draw_data(
/* if we have strokes for scenes (3d view)/clips (movie clip editor)
* and objects/tracks, multiple data blocks have to be drawn */
-static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy,
- int cfra, int dflag, const char spacetype)
+static void gp_draw_data_all(
+ RegionView3D *rv3d, Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy,
+ int cfra, int dflag, const char UNUSED(spacetype))
{
bGPdata *gpd_source = NULL;
- ToolSettings *ts;
- bGPDbrush *brush = NULL;
+ ToolSettings *ts = NULL;
+ Brush *brush = NULL;
if (scene) {
ts = scene->toolsettings;
- brush = BKE_gpencil_brush_getactive(ts);
- /* if no brushes, create default set */
- if (brush == NULL) {
- BKE_gpencil_brush_init_presets(ts);
- brush = BKE_gpencil_brush_getactive(ts);
- }
-
- if (spacetype == SPACE_VIEW3D) {
- gpd_source = (scene->gpd ? scene->gpd : NULL);
- }
- else if (spacetype == SPACE_CLIP && scene->clip) {
- /* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */
- gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL);
- }
+ brush = BKE_brush_getactive_gpencil(ts);
if (gpd_source) {
if (brush != NULL) {
- gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source,
- offsx, offsy, winx, winy, cfra, dflag);
+ gp_draw_data(
+ rv3d, brush, 1.0f, NULL, gpd_source,
+ offsx, offsy, winx, winy, cfra, dflag);
}
}
}
@@ -1554,76 +1693,70 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i
* if gpd_source == gpd, we don't have any object/track data and we can skip */
if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
if (brush != NULL) {
- gp_draw_data(brush, ts->gp_sculpt.alpha, gpd,
- offsx, offsy, winx, winy, cfra, dflag);
+ gp_draw_data(
+ rv3d, brush, 1.0f, NULL, gpd,
+ offsx, offsy, winx, winy, cfra, dflag);
}
}
}
/* ----- Grease Pencil Sketches Drawing API ------ */
-/* ............................
- * XXX
- * We need to review the calls below, since they may be/are not that suitable for
- * the new ways that we intend to be drawing data...
- * ............................ */
-/* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
-void ED_gpencil_draw_2dimage(const bContext *C)
+/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
+ * Note: this gets called twice - first time with only3d=true to draw 3d-strokes,
+ * second time with only3d=false for screen-aligned strokes */
+void ED_gpencil_draw_view3d(
+ wmWindowManager *wm,
+ Scene *scene,
+ ViewLayer *view_layer,
+ struct Depsgraph *depsgraph,
+ View3D *v3d,
+ ARegion *ar,
+ bool only3d)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
-
- int offsx, offsy, sizex, sizey;
- int dflag = GP_DRAWDATA_NOSTATUS;
+ int dflag = 0;
+ RegionView3D *rv3d = ar->regiondata;
+ int offsx, offsy, winx, winy;
- bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX
+ /* check that we have grease-pencil stuff to draw */
+ // XXX: This is the only place that still uses this function
+ bGPdata *gpd = ED_gpencil_data_get_active_v3d(view_layer);
if (gpd == NULL) return;
- /* calculate rect */
- switch (sa->spacetype) {
- case SPACE_IMAGE: /* image */
- case SPACE_CLIP: /* clip */
- {
- /* just draw using standard scaling (settings here are currently ignored anyways) */
- /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
- offsx = 0;
- offsy = 0;
- sizex = ar->winx;
- sizey = ar->winy;
+ /* when rendering to the offscreen buffer we don't want to
+ * deal with the camera border, otherwise map the coords to the camera border. */
+ if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
+ rctf rectf;
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */
- wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax);
+ offsx = round_fl_to_int(rectf.xmin);
+ offsy = round_fl_to_int(rectf.ymin);
+ winx = round_fl_to_int(rectf.xmax - rectf.xmin);
+ winy = round_fl_to_int(rectf.ymax - rectf.ymin);
+ }
+ else {
+ offsx = 0;
+ offsy = 0;
+ winx = ar->winx;
+ winy = ar->winy;
+ }
- dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK;
- break;
- }
- case SPACE_SEQ: /* sequence */
- {
- /* just draw using standard scaling (settings here are currently ignored anyways) */
- offsx = 0;
- offsy = 0;
- sizex = ar->winx;
- sizey = ar->winy;
-
- /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated
- * and everything moved to standard View2d
- */
- dflag |= GP_DRAWDATA_ONLYV2D;
- break;
- }
- default: /* for spacetype not yet handled */
- offsx = 0;
- offsy = 0;
- sizex = ar->winx;
- sizey = ar->winy;
-
- dflag |= GP_DRAWDATA_ONLYI2D;
- break;
+ /* set flags */
+ if (only3d) {
+ /* 3D strokes/3D space:
+ * - only 3D space points
+ * - don't status text either (as it's the wrong space)
+ */
+ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
}
- if (ED_screen_animation_playing(wm)) {
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ /* don't draw status text when "only render" flag is set */
+ dflag |= GP_DRAWDATA_NOSTATUS;
+ }
+
+ if ((wm == NULL) || ED_screen_animation_playing(wm)) {
/* don't show onionskins during animation playback/scrub (i.e. it obscures the poses)
* OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes)
*/
@@ -1631,85 +1764,46 @@ void ED_gpencil_draw_2dimage(const bContext *C)
}
/* draw it! */
- gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype);
+ gp_draw_data_all(rv3d, scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
}
-/* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly
- * Note: this gets called twice - first time with onlyv2d=true to draw 'canvas' strokes,
- * second time with onlyv2d=false for screen-aligned strokes */
-void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- int dflag = 0;
-
- /* check that we have grease-pencil stuff to draw */
- if (sa == NULL) return;
- bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX
- if (gpd == NULL) return;
-
- /* special hack for Image Editor */
- /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
- if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP))
- dflag |= GP_DRAWDATA_IEDITHACK;
-
- /* draw it! */
- if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
- if (ED_screen_animation_playing(wm)) dflag |= GP_DRAWDATA_NO_ONIONS;
-
- gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype);
-
- /* draw status text (if in screen/pixel-space) */
- if (!onlyv2d) {
- gp_draw_status_text(gpd, ar);
- }
-}
-
-/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
- * Note: this gets called twice - first time with only3d=true to draw 3d-strokes,
- * second time with only3d=false for screen-aligned strokes */
-void ED_gpencil_draw_view3d(wmWindowManager *wm,
- Scene *scene,
- ViewLayer *view_layer,
- struct Depsgraph *depsgraph,
- View3D *v3d,
- ARegion *ar,
- bool only3d)
+/* draw grease-pencil sketches to specified 3d-view for gp object
+ * assuming that matrices are already set correctly
+ */
+void ED_gpencil_draw_view3d_object(wmWindowManager *wm, Scene *scene, Depsgraph *depsgraph, Object *ob, View3D *v3d, ARegion *ar, bool only3d)
{
int dflag = 0;
RegionView3D *rv3d = ar->regiondata;
- int offsx, offsy, winx, winy;
+ int offsx, offsy, winx, winy;
/* check that we have grease-pencil stuff to draw */
- bGPdata *gpd = ED_gpencil_data_get_active_v3d(scene, view_layer);
+ bGPdata *gpd = ob->data;
if (gpd == NULL) return;
/* when rendering to the offscreen buffer we don't want to
- * deal with the camera border, otherwise map the coords to the camera border. */
+ * deal with the camera border, otherwise map the coords to the camera border. */
if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
rctf rectf;
ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */
offsx = round_fl_to_int(rectf.xmin);
offsy = round_fl_to_int(rectf.ymin);
- winx = round_fl_to_int(rectf.xmax - rectf.xmin);
- winy = round_fl_to_int(rectf.ymax - rectf.ymin);
+ winx = round_fl_to_int(rectf.xmax - rectf.xmin);
+ winy = round_fl_to_int(rectf.ymax - rectf.ymin);
}
else {
offsx = 0;
offsy = 0;
- winx = ar->winx;
- winy = ar->winy;
+ winx = ar->winx;
+ winy = ar->winy;
}
/* set flags */
if (only3d) {
/* 3D strokes/3D space:
- * - only 3D space points
- * - don't status text either (as it's the wrong space)
- */
+ * - only 3D space points
+ * - don't status text either (as it's the wrong space)
+ */
dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
}
@@ -1720,20 +1814,23 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm,
if ((wm == NULL) || ED_screen_animation_playing(wm)) {
/* don't show onionskins during animation playback/scrub (i.e. it obscures the poses)
- * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes)
- */
+ * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes)
+ */
dflag |= GP_DRAWDATA_NO_ONIONS;
}
/* draw it! */
- gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
+ ToolSettings *ts = scene->toolsettings;
+ Brush *brush = BKE_brush_getactive_gpencil(ts);
+ if (brush != NULL) {
+ gp_draw_data(rv3d, brush, 1.0f, ob, gpd,
+ offsx, offsy, winx, winy, CFRA, dflag);
+ }
}
-void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
+void ED_gpencil_draw_ex(RegionView3D *rv3d, Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
{
int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D;
- gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype);
+ gp_draw_data_all(rv3d, scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype);
}
-
-/* ************************************************** */
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index 5e62a87caf3..88f935eb8bf 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -492,6 +492,8 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* make a copy of stroke, then of its points array */
gpsn = MEM_dupallocN(gps);
gpsn->points = MEM_dupallocN(gps->points);
+ gpsn->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, gpsn);
/* duplicate triangle information */
gpsn->triangles = MEM_dupallocN(gps->triangles);
/* append stroke to frame */
diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c
new file mode 100644
index 00000000000..8a7128adde1
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_add_monkey.c
@@ -0,0 +1,1567 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez, Matias Mendiola
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/gpencil/gpencil_add_monkey.c
+ * \ingroup edgpencil
+ */
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "ED_gpencil.h"
+
+/* Definition of the most important info from a color */
+typedef struct ColorTemplate {
+ const char *name;
+ float line[4];
+ float fill[4];
+} ColorTemplate;
+
+/* Add color an ensure duplications (matched by name) */
+static int gpencil_monkey_color(Main *bmain, Object *ob, const ColorTemplate *pct)
+{
+ Material *ma = NULL;
+ Material ***matar = give_matarar(ob);
+ short *totcol = give_totcolp(ob);
+ for (short i = 0; i < *totcol; i++) {
+ ma = (*matar)[i];
+ if (STREQ(ma->id.name, pct->name)) {
+ return i;
+ }
+ }
+
+ /* create a new one */
+ BKE_object_material_slot_add(bmain, ob);
+ ma = BKE_material_add_gpencil(bmain, pct->name);
+ assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_EXISTING);
+
+ copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
+ copy_v4_v4(ma->gp_style->fill_rgba, pct->fill);
+
+ return BKE_object_material_slot_find_index(ob, ma) - 1;
+}
+
+/* ***************************************************************** */
+/* Monkey Geometry */
+
+static const float data0[538 * GP_PRIM_DATABUF_SIZE] = {
+ -0.509f, 0.0f, -0.156f, 0.267f, 0.362f, -0.522f, 0.0f, -0.159f, 0.31f, 0.407f, -0.531f, 0.0f, -0.16f, 0.347f, 0.426f, -0.543f, -0.0f, -0.162f, 0.38f, 0.439f,
+ -0.554f, -0.0f, -0.163f, 0.409f, 0.448f, -0.566f, -0.0f, -0.165f, 0.433f, 0.458f, -0.578f, -0.0f, -0.167f, 0.454f, 0.478f, -0.591f, -0.0f, -0.168f, 0.471f, 0.5f,
+ -0.604f, -0.0f, -0.169f, 0.485f, 0.51f, -0.619f, -0.0f, -0.171f, 0.496f, 0.516f, -0.634f, -0.0f, -0.171f, 0.504f, 0.519f, -0.649f, -0.0f, -0.171f, 0.511f, 0.519f,
+ -0.665f, -0.0f, -0.17f, 0.516f, 0.521f, -0.681f, -0.0f, -0.17f, 0.521f, 0.53f, -0.697f, -0.0f, -0.169f, 0.524f, 0.533f, -0.713f, -0.0f, -0.167f, 0.527f, 0.533f,
+ -0.729f, 0.0f, -0.165f, 0.53f, 0.534f, -0.745f, 0.0f, -0.161f, 0.531f, 0.534f, -0.761f, 0.0f, -0.157f, 0.533f, 0.535f, -0.777f, 0.0f, -0.153f, 0.534f, 0.535f,
+ -0.792f, 0.0f, -0.148f, 0.535f, 0.536f, -0.808f, 0.0f, -0.144f, 0.535f, 0.535f, -0.822f, 0.0f, -0.139f, 0.536f, 0.537f, -0.837f, 0.0f, -0.133f, 0.536f, 0.537f,
+ -0.852f, 0.0f, -0.128f, 0.536f, 0.537f, -0.866f, 0.0f, -0.122f, 0.536f, 0.537f, -0.88f, 0.0f, -0.115f, 0.536f, 0.537f, -0.894f, 0.0f, -0.109f, 0.536f, 0.537f,
+ -0.908f, 0.0f, -0.101f, 0.535f, 0.535f, -0.922f, 0.0f, -0.092f, 0.535f, 0.535f, -0.936f, 0.0f, -0.082f, 0.534f, 0.534f, -0.949f, 0.0f, -0.072f, 0.534f, 0.534f,
+ -0.963f, 0.0f, -0.061f, 0.534f, 0.534f, -0.976f, 0.0f, -0.05f, 0.534f, 0.534f, -0.988f, 0.0f, -0.039f, 0.534f, 0.534f, -1.0f, 0.0f, -0.028f, 0.533f, 0.534f,
+ -1.011f, 0.0f, -0.017f, 0.533f, 0.533f, -1.022f, 0.0f, -0.007f, 0.533f, 0.534f, -1.033f, 0.0f, 0.004f, 0.533f, 0.533f, -1.043f, 0.0f, 0.014f, 0.532f, 0.532f,
+ -1.053f, 0.0f, 0.025f, 0.532f, 0.532f, -1.062f, 0.0f, 0.036f, 0.531f, 0.531f, -1.071f, 0.0f, 0.046f, 0.531f, 0.531f, -1.078f, 0.0f, 0.057f, 0.531f, 0.531f,
+ -1.085f, 0.0f, 0.068f, 0.531f, 0.531f, -1.092f, 0.0f, 0.08f, 0.532f, 0.532f, -1.098f, 0.0f, 0.091f, 0.533f, 0.533f, -1.104f, 0.0f, 0.105f, 0.535f, 0.535f,
+ -1.11f, 0.0f, 0.119f, 0.539f, 0.539f, -1.115f, 0.0f, 0.133f, 0.54f, 0.54f, -1.118f, 0.0f, 0.148f, 0.541f, 0.541f, -1.121f, 0.0f, 0.162f, 0.542f, 0.542f,
+ -1.123f, 0.0f, 0.177f, 0.542f, 0.542f, -1.125f, 0.0f, 0.193f, 0.543f, 0.543f, -1.125f, 0.0f, 0.208f, 0.543f, 0.543f, -1.125f, 0.0f, 0.225f, 0.543f, 0.543f,
+ -1.124f, 0.0f, 0.241f, 0.545f, 0.545f, -1.122f, 0.0f, 0.258f, 0.546f, 0.546f, -1.119f, 0.0f, 0.274f, 0.548f, 0.548f, -1.116f, 0.0f, 0.29f, 0.549f, 0.549f,
+ -1.111f, 0.0f, 0.305f, 0.549f, 0.549f, -1.106f, 0.0f, 0.318f, 0.549f, 0.549f, -1.1f, 0.0f, 0.33f, 0.549f, 0.549f, -1.094f, 0.0f, 0.34f, 0.549f, 0.549f,
+ -1.087f, 0.0f, 0.349f, 0.55f, 0.55f, -1.08f, 0.0f, 0.357f, 0.549f, 0.549f, -1.072f, 0.0f, 0.365f, 0.55f, 0.55f, -1.063f, 0.0f, 0.372f, 0.551f, 0.551f,
+ -1.054f, 0.0f, 0.379f, 0.552f, 0.552f, -1.044f, 0.0f, 0.385f, 0.553f, 0.553f, -1.034f, 0.0f, 0.391f, 0.553f, 0.553f, -1.024f, 0.0f, 0.396f, 0.554f, 0.554f,
+ -1.013f, 0.0f, 0.401f, 0.554f, 0.554f, -1.003f, 0.0f, 0.405f, 0.554f, 0.554f, -0.991f, 0.0f, 0.409f, 0.554f, 0.554f, -0.978f, 0.0f, 0.412f, 0.555f, 0.555f,
+ -0.964f, -0.0f, 0.414f, 0.555f, 0.555f, -0.949f, -0.0f, 0.414f, 0.556f, 0.556f, -0.934f, -0.0f, 0.413f, 0.556f, 0.556f, -0.919f, -0.0f, 0.412f, 0.557f, 0.557f,
+ -0.905f, -0.0f, 0.41f, 0.557f, 0.557f, -0.892f, -0.0f, 0.406f, 0.557f, 0.557f, -0.879f, -0.0f, 0.402f, 0.557f, 0.558f, -0.867f, -0.0f, 0.398f, 0.557f, 0.557f,
+ -0.855f, -0.0f, 0.394f, 0.557f, 0.557f, -0.843f, -0.0f, 0.388f, 0.557f, 0.557f, -0.831f, -0.0f, 0.381f, 0.558f, 0.557f, -0.82f, -0.0f, 0.375f, 0.558f, 0.557f,
+ -0.81f, -0.0f, 0.368f, 0.558f, 0.558f, -0.801f, -0.0f, 0.362f, 0.558f, 0.558f, -0.793f, -0.0f, 0.357f, 0.557f, 0.559f, -0.784f, 0.0f, 0.353f, 0.557f, 0.559f,
+ -0.776f, 0.0f, 0.35f, 0.556f, 0.559f, -0.768f, 0.0f, 0.348f, 0.556f, 0.559f, -0.76f, 0.0f, 0.346f, 0.555f, 0.559f, -0.752f, 0.0f, 0.346f, 0.554f, 0.559f,
+ -0.744f, 0.0f, 0.347f, 0.553f, 0.554f, -0.737f, 0.0f, 0.348f, 0.552f, 0.548f, -0.729f, 0.0f, 0.351f, 0.551f, 0.544f, -0.723f, 0.0f, 0.355f, 0.551f, 0.546f,
+ -0.716f, 0.0f, 0.36f, 0.55f, 0.546f, -0.709f, 0.0f, 0.366f, 0.55f, 0.547f, -0.702f, 0.0f, 0.372f, 0.549f, 0.547f, -0.696f, 0.0f, 0.379f, 0.549f, 0.547f,
+ -0.689f, 0.0f, 0.386f, 0.549f, 0.548f, -0.683f, 0.0f, 0.394f, 0.549f, 0.548f, -0.676f, 0.0f, 0.403f, 0.549f, 0.549f, -0.67f, 0.0f, 0.413f, 0.549f, 0.548f,
+ -0.664f, 0.0f, 0.422f, 0.549f, 0.549f, -0.658f, 0.0f, 0.432f, 0.55f, 0.549f, -0.652f, 0.0f, 0.441f, 0.551f, 0.548f, -0.646f, 0.0f, 0.451f, 0.552f, 0.548f,
+ -0.639f, 0.0f, 0.46f, 0.554f, 0.548f, -0.632f, 0.0f, 0.469f, 0.556f, 0.549f, -0.624f, 0.0f, 0.478f, 0.559f, 0.549f, -0.616f, 0.0f, 0.487f, 0.563f, 0.549f,
+ -0.609f, 0.0f, 0.497f, 0.567f, 0.549f, -0.6f, 0.0f, 0.507f, 0.572f, 0.558f, -0.592f, 0.0f, 0.518f, 0.577f, 0.574f, -0.584f, 0.0f, 0.528f, 0.582f, 0.587f,
+ -0.575f, 0.0f, 0.538f, 0.586f, 0.592f, -0.566f, 0.0f, 0.548f, 0.591f, 0.595f, -0.556f, 0.0f, 0.557f, 0.594f, 0.597f, -0.546f, 0.0f, 0.567f, 0.597f, 0.598f,
+ -0.536f, 0.0f, 0.577f, 0.6f, 0.6f, -0.525f, 0.0f, 0.586f, 0.602f, 0.603f, -0.514f, 0.0f, 0.596f, 0.604f, 0.605f, -0.503f, 0.0f, 0.606f, 0.605f, 0.606f,
+ -0.492f, 0.0f, 0.615f, 0.606f, 0.607f, -0.482f, 0.0f, 0.624f, 0.607f, 0.607f, -0.471f, 0.0f, 0.632f, 0.608f, 0.607f, -0.462f, 0.0f, 0.64f, 0.609f, 0.607f,
+ -0.453f, 0.0f, 0.647f, 0.61f, 0.61f, -0.444f, 0.0f, 0.654f, 0.612f, 0.611f, -0.435f, 0.0f, 0.66f, 0.614f, 0.613f, -0.427f, 0.0f, 0.666f, 0.616f, 0.615f,
+ -0.418f, 0.0f, 0.672f, 0.617f, 0.618f, -0.409f, 0.0f, 0.677f, 0.619f, 0.621f, -0.399f, 0.0f, 0.683f, 0.621f, 0.622f, -0.389f, 0.0f, 0.69f, 0.623f, 0.623f,
+ -0.379f, 0.0f, 0.696f, 0.624f, 0.624f, -0.368f, 0.0f, 0.702f, 0.626f, 0.626f, -0.356f, 0.0f, 0.708f, 0.628f, 0.628f, -0.345f, 0.0f, 0.713f, 0.63f, 0.63f,
+ -0.333f, 0.0f, 0.719f, 0.633f, 0.631f, -0.32f, 0.0f, 0.724f, 0.637f, 0.632f, -0.307f, 0.0f, 0.729f, 0.641f, 0.64f, -0.294f, 0.0f, 0.732f, 0.646f, 0.644f,
+ -0.281f, 0.0f, 0.736f, 0.65f, 0.655f, -0.268f, 0.0f, 0.739f, 0.654f, 0.657f, -0.255f, 0.0f, 0.742f, 0.657f, 0.658f, -0.243f, 0.0f, 0.745f, 0.659f, 0.661f,
+ -0.23f, 0.0f, 0.747f, 0.662f, 0.663f, -0.217f, 0.0f, 0.75f, 0.664f, 0.664f, -0.203f, 0.0f, 0.753f, 0.666f, 0.666f, -0.19f, 0.0f, 0.755f, 0.667f, 0.668f,
+ -0.177f, 0.0f, 0.757f, 0.669f, 0.67f, -0.163f, 0.0f, 0.76f, 0.671f, 0.671f, -0.15f, 0.0f, 0.762f, 0.673f, 0.672f, -0.136f, 0.0f, 0.764f, 0.674f, 0.674f,
+ -0.122f, 0.0f, 0.767f, 0.676f, 0.676f, -0.108f, 0.0f, 0.769f, 0.677f, 0.678f, -0.093f, 0.0f, 0.771f, 0.678f, 0.68f, -0.079f, 0.0f, 0.773f, 0.678f, 0.68f,
+ -0.064f, 0.0f, 0.774f, 0.679f, 0.679f, -0.049f, 0.0f, 0.775f, 0.68f, 0.68f, -0.033f, 0.0f, 0.775f, 0.68f, 0.68f, -0.018f, 0.0f, 0.776f, 0.68f, 0.68f,
+ -0.002f, 0.0f, 0.776f, 0.681f, 0.68f, 0.013f, 0.0f, 0.777f, 0.681f, 0.681f, 0.029f, 0.0f, 0.777f, 0.682f, 0.681f, 0.045f, 0.0f, 0.777f, 0.682f, 0.681f,
+ 0.061f, 0.0f, 0.777f, 0.683f, 0.683f, 0.077f, 0.0f, 0.776f, 0.683f, 0.683f, 0.094f, 0.0f, 0.775f, 0.684f, 0.684f, 0.11f, 0.0f, 0.774f, 0.685f, 0.683f,
+ 0.126f, 0.0f, 0.773f, 0.685f, 0.685f, 0.142f, 0.0f, 0.771f, 0.687f, 0.685f, 0.158f, 0.0f, 0.769f, 0.688f, 0.685f, 0.174f, 0.0f, 0.767f, 0.69f, 0.686f,
+ 0.19f, 0.0f, 0.765f, 0.691f, 0.692f, 0.206f, 0.0f, 0.762f, 0.693f, 0.694f, 0.222f, 0.0f, 0.757f, 0.695f, 0.696f, 0.238f, 0.0f, 0.752f, 0.697f, 0.697f,
+ 0.254f, 0.0f, 0.747f, 0.699f, 0.698f, 0.27f, 0.0f, 0.742f, 0.7f, 0.7f, 0.286f, 0.0f, 0.736f, 0.702f, 0.702f, 0.302f, 0.0f, 0.73f, 0.704f, 0.704f,
+ 0.318f, 0.0f, 0.724f, 0.705f, 0.71f, 0.335f, 0.0f, 0.717f, 0.707f, 0.71f, 0.351f, 0.0f, 0.709f, 0.708f, 0.71f, 0.367f, 0.0f, 0.701f, 0.709f, 0.711f,
+ 0.382f, 0.0f, 0.692f, 0.71f, 0.713f, 0.397f, 0.0f, 0.683f, 0.711f, 0.713f, 0.41f, 0.0f, 0.675f, 0.712f, 0.713f, 0.422f, 0.0f, 0.666f, 0.712f, 0.714f,
+ 0.434f, 0.0f, 0.658f, 0.713f, 0.714f, 0.446f, 0.0f, 0.649f, 0.714f, 0.714f, 0.458f, 0.0f, 0.641f, 0.714f, 0.714f, 0.47f, 0.0f, 0.632f, 0.715f, 0.715f,
+ 0.483f, 0.0f, 0.622f, 0.715f, 0.716f, 0.496f, 0.0f, 0.611f, 0.715f, 0.716f, 0.51f, 0.0f, 0.6f, 0.716f, 0.717f, 0.523f, 0.0f, 0.588f, 0.716f, 0.716f,
+ 0.536f, 0.0f, 0.576f, 0.717f, 0.717f, 0.55f, 0.0f, 0.563f, 0.717f, 0.717f, 0.564f, 0.0f, 0.549f, 0.717f, 0.717f, 0.577f, 0.0f, 0.536f, 0.718f, 0.717f,
+ 0.59f, 0.0f, 0.522f, 0.718f, 0.717f, 0.603f, 0.0f, 0.508f, 0.718f, 0.718f, 0.615f, 0.0f, 0.496f, 0.718f, 0.718f, 0.625f, 0.0f, 0.484f, 0.718f, 0.718f,
+ 0.635f, 0.0f, 0.473f, 0.719f, 0.718f, 0.645f, 0.0f, 0.461f, 0.719f, 0.718f, 0.654f, 0.0f, 0.45f, 0.719f, 0.718f, 0.662f, 0.0f, 0.44f, 0.719f, 0.719f,
+ 0.67f, 0.0f, 0.431f, 0.719f, 0.719f, 0.676f, 0.0f, 0.422f, 0.719f, 0.719f, 0.682f, 0.0f, 0.414f, 0.719f, 0.719f, 0.687f, 0.0f, 0.407f, 0.719f, 0.719f,
+ 0.692f, 0.0f, 0.4f, 0.719f, 0.719f, 0.697f, 0.0f, 0.394f, 0.719f, 0.719f, 0.701f, 0.0f, 0.388f, 0.718f, 0.718f, 0.705f, 0.0f, 0.383f, 0.718f, 0.717f,
+ 0.708f, 0.0f, 0.378f, 0.718f, 0.717f, 0.711f, 0.0f, 0.374f, 0.717f, 0.717f, 0.714f, 0.0f, 0.37f, 0.717f, 0.717f, 0.717f, 0.0f, 0.366f, 0.717f, 0.717f,
+ 0.719f, 0.0f, 0.362f, 0.718f, 0.717f, 0.722f, 0.0f, 0.359f, 0.718f, 0.718f, 0.724f, 0.0f, 0.356f, 0.718f, 0.717f, 0.727f, 0.0f, 0.352f, 0.717f, 0.719f,
+ 0.73f, 0.0f, 0.349f, 0.717f, 0.719f, 0.734f, 0.0f, 0.347f, 0.715f, 0.719f, 0.737f, 0.0f, 0.344f, 0.714f, 0.714f, 0.742f, 0.0f, 0.341f, 0.713f, 0.709f,
+ 0.746f, 0.0f, 0.339f, 0.714f, 0.707f, 0.751f, 0.0f, 0.336f, 0.718f, 0.704f, 0.757f, 0.0f, 0.334f, 0.724f, 0.705f, 0.763f, 0.0f, 0.332f, 0.732f, 0.705f,
+ 0.769f, -0.0f, 0.329f, 0.742f, 0.704f, 0.775f, -0.0f, 0.328f, 0.753f, 0.713f, 0.782f, -0.0f, 0.327f, 0.764f, 0.804f, 0.789f, -0.0f, 0.327f, 0.774f, 0.813f,
+ 0.797f, -0.0f, 0.327f, 0.783f, 0.815f, 0.805f, -0.0f, 0.328f, 0.791f, 0.815f, 0.814f, -0.0f, 0.329f, 0.797f, 0.816f, 0.823f, -0.0f, 0.331f, 0.802f, 0.815f,
+ 0.832f, 0.0f, 0.335f, 0.806f, 0.816f, 0.841f, 0.0f, 0.341f, 0.809f, 0.816f, 0.851f, 0.0f, 0.346f, 0.811f, 0.816f, 0.861f, 0.0f, 0.351f, 0.812f, 0.816f,
+ 0.871f, 0.0f, 0.356f, 0.813f, 0.815f, 0.881f, 0.0f, 0.361f, 0.814f, 0.816f, 0.893f, 0.0f, 0.365f, 0.814f, 0.816f, 0.906f, 0.0f, 0.368f, 0.814f, 0.817f,
+ 0.922f, 0.0f, 0.372f, 0.813f, 0.816f, 0.939f, 0.0f, 0.375f, 0.812f, 0.817f, 0.957f, 0.0f, 0.377f, 0.811f, 0.817f, 0.977f, 0.0f, 0.379f, 0.81f, 0.815f,
+ 0.995f, 0.0f, 0.38f, 0.808f, 0.813f, 1.012f, 0.0f, 0.379f, 0.806f, 0.807f, 1.028f, 0.0f, 0.377f, 0.803f, 0.803f, 1.042f, 0.0f, 0.374f, 0.8f, 0.801f,
+ 1.054f, 0.0f, 0.371f, 0.797f, 0.8f, 1.065f, 0.0f, 0.366f, 0.794f, 0.8f, 1.076f, 0.0f, 0.361f, 0.791f, 0.792f, 1.085f, 0.0f, 0.355f, 0.788f, 0.781f,
+ 1.093f, 0.0f, 0.348f, 0.785f, 0.781f, 1.1f, 0.0f, 0.34f, 0.783f, 0.78f, 1.106f, 0.0f, 0.33f, 0.782f, 0.78f, 1.113f, 0.0f, 0.321f, 0.781f, 0.778f,
+ 1.117f, 0.0f, 0.31f, 0.78f, 0.777f, 1.122f, -0.0f, 0.299f, 0.779f, 0.777f, 1.125f, -0.0f, 0.286f, 0.778f, 0.776f, 1.129f, -0.0f, 0.274f, 0.778f, 0.777f,
+ 1.131f, -0.0f, 0.262f, 0.778f, 0.777f, 1.132f, -0.0f, 0.249f, 0.777f, 0.777f, 1.134f, -0.0f, 0.237f, 0.777f, 0.778f, 1.134f, -0.0f, 0.225f, 0.777f, 0.778f,
+ 1.135f, -0.0f, 0.213f, 0.776f, 0.777f, 1.134f, -0.0f, 0.201f, 0.776f, 0.776f, 1.134f, -0.0f, 0.189f, 0.776f, 0.775f, 1.132f, -0.0f, 0.177f, 0.775f, 0.776f,
+ 1.13f, -0.0f, 0.164f, 0.775f, 0.775f, 1.129f, -0.0f, 0.152f, 0.774f, 0.774f, 1.126f, -0.0f, 0.141f, 0.774f, 0.773f, 1.122f, -0.0f, 0.13f, 0.774f, 0.772f,
+ 1.118f, -0.0f, 0.118f, 0.773f, 0.772f, 1.113f, -0.0f, 0.108f, 0.773f, 0.773f, 1.107f, -0.0f, 0.097f, 0.773f, 0.774f, 1.102f, -0.0f, 0.087f, 0.772f, 0.773f,
+ 1.095f, -0.0f, 0.077f, 0.772f, 0.773f, 1.088f, -0.0f, 0.067f, 0.771f, 0.772f, 1.081f, -0.0f, 0.057f, 0.771f, 0.773f, 1.073f, -0.0f, 0.048f, 0.77f, 0.772f,
+ 1.066f, -0.0f, 0.038f, 0.769f, 0.767f, 1.058f, -0.0f, 0.029f, 0.768f, 0.766f, 1.05f, -0.0f, 0.019f, 0.768f, 0.765f, 1.041f, -0.0f, 0.011f, 0.767f, 0.765f,
+ 1.032f, -0.0f, 0.003f, 0.767f, 0.766f, 1.023f, -0.0f, -0.004f, 0.766f, 0.765f, 1.013f, -0.0f, -0.011f, 0.766f, 0.765f, 1.003f, -0.0f, -0.019f, 0.765f, 0.766f,
+ 0.993f, -0.0f, -0.026f, 0.765f, 0.765f, 0.983f, -0.0f, -0.034f, 0.764f, 0.765f, 0.972f, -0.0f, -0.041f, 0.762f, 0.765f, 0.962f, -0.0f, -0.048f, 0.761f, 0.765f,
+ 0.951f, -0.0f, -0.055f, 0.759f, 0.762f, 0.94f, -0.0f, -0.063f, 0.756f, 0.761f, 0.929f, -0.0f, -0.07f, 0.754f, 0.755f, 0.918f, -0.0f, -0.078f, 0.751f, 0.751f,
+ 0.907f, -0.0f, -0.085f, 0.748f, 0.747f, 0.896f, -0.0f, -0.092f, 0.745f, 0.744f, 0.884f, -0.0f, -0.099f, 0.742f, 0.742f, 0.873f, -0.0f, -0.105f, 0.739f, 0.738f,
+ 0.861f, -0.0f, -0.11f, 0.736f, 0.737f, 0.849f, 0.0f, -0.115f, 0.733f, 0.731f, 0.836f, 0.0f, -0.119f, 0.73f, 0.73f, 0.823f, 0.0f, -0.124f, 0.728f, 0.727f,
+ 0.81f, 0.0f, -0.128f, 0.725f, 0.725f, 0.796f, 0.0f, -0.132f, 0.723f, 0.723f, 0.783f, 0.0f, -0.136f, 0.72f, 0.719f, 0.77f, 0.0f, -0.141f, 0.718f, 0.717f,
+ 0.756f, 0.0f, -0.145f, 0.715f, 0.712f, 0.742f, 0.0f, -0.15f, 0.713f, 0.708f, 0.728f, 0.0f, -0.152f, 0.711f, 0.707f, 0.713f, 0.0f, -0.155f, 0.709f, 0.706f,
+ 0.699f, 0.0f, -0.156f, 0.706f, 0.706f, 0.684f, 0.0f, -0.158f, 0.704f, 0.705f, 0.67f, 0.0f, -0.159f, 0.702f, 0.705f, 0.656f, 0.0f, -0.16f, 0.7f, 0.704f,
+ 0.642f, 0.0f, -0.161f, 0.698f, 0.702f, 0.628f, 0.0f, -0.161f, 0.695f, 0.698f, 0.614f, 0.0f, -0.162f, 0.693f, 0.695f, 0.6f, 0.0f, -0.162f, 0.691f, 0.691f,
+ 0.587f, 0.0f, -0.162f, 0.688f, 0.686f, 0.574f, 0.0f, -0.162f, 0.686f, 0.685f, 0.561f, 0.0f, -0.161f, 0.683f, 0.683f, 0.548f, 0.0f, -0.161f, 0.681f, 0.683f,
+ 0.535f, 0.0f, -0.161f, 0.678f, 0.678f, 0.523f, 0.0f, -0.16f, 0.676f, 0.676f, 0.512f, 0.0f, -0.16f, 0.673f, 0.674f, 0.501f, 0.0f, -0.16f, 0.671f, 0.67f,
+ 0.49f, 0.0f, -0.16f, 0.668f, 0.668f, 0.48f, 0.0f, -0.161f, 0.666f, 0.663f, 0.469f, 0.0f, -0.162f, 0.665f, 0.66f, 0.458f, 0.0f, -0.165f, 0.663f, 0.66f,
+ 0.447f, 0.0f, -0.167f, 0.662f, 0.659f, 0.437f, 0.0f, -0.171f, 0.661f, 0.659f, 0.426f, 0.0f, -0.175f, 0.66f, 0.659f, 0.415f, 0.0f, -0.18f, 0.66f, 0.659f,
+ 0.404f, 0.0f, -0.185f, 0.659f, 0.659f, 0.393f, 0.0f, -0.191f, 0.659f, 0.657f, 0.383f, 0.0f, -0.196f, 0.659f, 0.657f, 0.373f, 0.0f, -0.202f, 0.658f, 0.659f,
+ 0.363f, -0.0f, -0.208f, 0.658f, 0.658f, 0.353f, -0.0f, -0.215f, 0.658f, 0.659f, 0.344f, -0.0f, -0.223f, 0.658f, 0.659f, 0.336f, -0.0f, -0.23f, 0.658f, 0.659f,
+ 0.327f, -0.0f, -0.238f, 0.658f, 0.658f, 0.319f, -0.0f, -0.245f, 0.657f, 0.657f, 0.312f, -0.0f, -0.253f, 0.657f, 0.656f, 0.305f, -0.0f, -0.261f, 0.656f, 0.658f,
+ 0.299f, -0.0f, -0.269f, 0.655f, 0.658f, 0.293f, 0.0f, -0.278f, 0.653f, 0.657f, 0.288f, 0.0f, -0.287f, 0.65f, 0.657f, 0.283f, 0.0f, -0.295f, 0.646f, 0.656f,
+ 0.279f, 0.0f, -0.304f, 0.642f, 0.655f, 0.275f, 0.0f, -0.313f, 0.637f, 0.642f, 0.271f, 0.0f, -0.322f, 0.633f, 0.637f, 0.268f, 0.0f, -0.331f, 0.628f, 0.609f,
+ 0.265f, 0.0f, -0.341f, 0.624f, 0.607f, 0.263f, 0.0f, -0.35f, 0.62f, 0.608f, 0.261f, 0.0f, -0.359f, 0.617f, 0.608f, 0.259f, 0.0f, -0.369f, 0.614f, 0.607f,
+ 0.258f, 0.0f, -0.379f, 0.612f, 0.606f, 0.257f, 0.0f, -0.389f, 0.61f, 0.606f, 0.258f, 0.0f, -0.399f, 0.609f, 0.605f, 0.258f, 0.0f, -0.41f, 0.608f, 0.604f,
+ 0.26f, 0.0f, -0.421f, 0.608f, 0.606f, 0.263f, 0.0f, -0.431f, 0.607f, 0.606f, 0.266f, 0.0f, -0.441f, 0.607f, 0.606f, 0.27f, 0.0f, -0.452f, 0.606f, 0.607f,
+ 0.274f, 0.0f, -0.463f, 0.606f, 0.607f, 0.279f, 0.0f, -0.475f, 0.605f, 0.607f, 0.283f, 0.0f, -0.487f, 0.604f, 0.607f, 0.288f, 0.0f, -0.498f, 0.603f, 0.607f,
+ 0.293f, 0.0f, -0.511f, 0.601f, 0.607f, 0.297f, 0.0f, -0.523f, 0.598f, 0.606f, 0.301f, 0.0f, -0.536f, 0.595f, 0.605f, 0.305f, 0.0f, -0.549f, 0.591f, 0.602f,
+ 0.309f, 0.0f, -0.562f, 0.588f, 0.597f, 0.312f, 0.0f, -0.576f, 0.583f, 0.585f, 0.315f, 0.0f, -0.59f, 0.579f, 0.577f, 0.318f, 0.0f, -0.604f, 0.574f, 0.576f,
+ 0.321f, 0.0f, -0.618f, 0.569f, 0.57f, 0.323f, 0.0f, -0.633f, 0.564f, 0.564f, 0.326f, 0.0f, -0.647f, 0.559f, 0.554f, 0.328f, 0.0f, -0.663f, 0.555f, 0.549f,
+ 0.33f, 0.0f, -0.678f, 0.551f, 0.546f, 0.332f, 0.0f, -0.693f, 0.547f, 0.543f, 0.334f, 0.0f, -0.709f, 0.544f, 0.543f, 0.336f, 0.0f, -0.726f, 0.541f, 0.541f,
+ 0.338f, 0.0f, -0.742f, 0.538f, 0.54f, 0.338f, 0.0f, -0.758f, 0.536f, 0.538f, 0.338f, 0.0f, -0.773f, 0.534f, 0.53f, 0.337f, 0.0f, -0.787f, 0.532f, 0.528f,
+ 0.337f, 0.0f, -0.801f, 0.53f, 0.528f, 0.336f, 0.0f, -0.814f, 0.529f, 0.528f, 0.334f, 0.0f, -0.827f, 0.527f, 0.528f, 0.333f, 0.0f, -0.84f, 0.525f, 0.529f,
+ 0.331f, 0.0f, -0.853f, 0.523f, 0.529f, 0.328f, 0.0f, -0.866f, 0.521f, 0.528f, 0.324f, 0.0f, -0.877f, 0.519f, 0.516f, 0.32f, 0.0f, -0.889f, 0.516f, 0.515f,
+ 0.315f, 0.0f, -0.9f, 0.513f, 0.515f, 0.31f, 0.0f, -0.91f, 0.51f, 0.514f, 0.304f, 0.0f, -0.921f, 0.507f, 0.513f, 0.297f, 0.0f, -0.931f, 0.505f, 0.507f,
+ 0.289f, 0.0f, -0.94f, 0.502f, 0.498f, 0.281f, 0.0f, -0.948f, 0.499f, 0.494f, 0.272f, 0.0f, -0.956f, 0.497f, 0.491f, 0.262f, 0.0f, -0.963f, 0.495f, 0.49f,
+ 0.253f, 0.0f, -0.969f, 0.494f, 0.491f, 0.242f, 0.0f, -0.975f, 0.493f, 0.491f, 0.231f, 0.0f, -0.98f, 0.492f, 0.49f, 0.22f, 0.0f, -0.986f, 0.491f, 0.489f,
+ 0.208f, 0.0f, -0.99f, 0.491f, 0.49f, 0.195f, 0.0f, -0.994f, 0.491f, 0.491f, 0.181f, 0.0f, -0.998f, 0.491f, 0.491f, 0.168f, 0.0f, -1.001f, 0.491f, 0.492f,
+ 0.154f, 0.0f, -1.005f, 0.491f, 0.492f, 0.141f, 0.0f, -1.008f, 0.492f, 0.492f, 0.126f, 0.0f, -1.01f, 0.492f, 0.492f, 0.112f, 0.0f, -1.011f, 0.492f, 0.492f,
+ 0.097f, 0.0f, -1.013f, 0.492f, 0.492f, 0.081f, 0.0f, -1.013f, 0.492f, 0.492f, 0.066f, 0.0f, -1.014f, 0.493f, 0.493f, 0.05f, 0.0f, -1.014f, 0.493f, 0.494f,
+ 0.035f, 0.0f, -1.014f, 0.493f, 0.494f, 0.019f, 0.0f, -1.013f, 0.493f, 0.494f, 0.004f, 0.0f, -1.012f, 0.493f, 0.494f, -0.011f, 0.0f, -1.011f, 0.493f, 0.493f,
+ -0.026f, 0.0f, -1.01f, 0.492f, 0.493f, -0.041f, 0.0f, -1.008f, 0.492f, 0.492f, -0.056f, 0.0f, -1.006f, 0.492f, 0.492f, -0.07f, 0.0f, -1.004f, 0.491f, 0.492f,
+ -0.084f, 0.0f, -1.001f, 0.491f, 0.492f, -0.098f, 0.0f, -0.999f, 0.491f, 0.491f, -0.112f, 0.0f, -0.995f, 0.491f, 0.49f, -0.125f, 0.0f, -0.992f, 0.49f, 0.49f,
+ -0.138f, 0.0f, -0.987f, 0.49f, 0.491f, -0.15f, 0.0f, -0.983f, 0.49f, 0.49f, -0.162f, 0.0f, -0.978f, 0.49f, 0.49f, -0.174f, 0.0f, -0.973f, 0.489f, 0.489f,
+ -0.185f, 0.0f, -0.967f, 0.489f, 0.488f, -0.196f, 0.0f, -0.961f, 0.489f, 0.489f, -0.207f, 0.0f, -0.955f, 0.489f, 0.489f, -0.218f, 0.0f, -0.949f, 0.489f, 0.49f,
+ -0.229f, 0.0f, -0.943f, 0.489f, 0.489f, -0.24f, 0.0f, -0.936f, 0.489f, 0.489f, -0.25f, 0.0f, -0.929f, 0.489f, 0.489f, -0.261f, 0.0f, -0.922f, 0.489f, 0.489f,
+ -0.271f, 0.0f, -0.914f, 0.489f, 0.49f, -0.28f, 0.0f, -0.907f, 0.49f, 0.49f, -0.289f, 0.0f, -0.898f, 0.49f, 0.489f, -0.298f, 0.0f, -0.89f, 0.49f, 0.489f,
+ -0.306f, 0.0f, -0.882f, 0.49f, 0.49f, -0.314f, 0.0f, -0.875f, 0.491f, 0.489f, -0.322f, 0.0f, -0.866f, 0.492f, 0.489f, -0.328f, 0.0f, -0.857f, 0.492f, 0.489f,
+ -0.333f, 0.0f, -0.847f, 0.493f, 0.49f, -0.336f, 0.0f, -0.836f, 0.494f, 0.488f, -0.338f, 0.0f, -0.824f, 0.496f, 0.49f, -0.338f, 0.0f, -0.811f, 0.497f, 0.49f,
+ -0.338f, 0.0f, -0.798f, 0.499f, 0.491f, -0.337f, 0.0f, -0.785f, 0.501f, 0.497f, -0.337f, 0.0f, -0.772f, 0.503f, 0.5f, -0.337f, 0.0f, -0.759f, 0.505f, 0.504f,
+ -0.336f, -0.0f, -0.746f, 0.507f, 0.505f, -0.336f, -0.0f, -0.733f, 0.51f, 0.51f, -0.335f, -0.0f, -0.719f, 0.512f, 0.513f, -0.334f, -0.0f, -0.706f, 0.515f, 0.515f,
+ -0.333f, -0.0f, -0.692f, 0.518f, 0.516f, -0.332f, -0.0f, -0.678f, 0.52f, 0.522f, -0.331f, -0.0f, -0.665f, 0.523f, 0.523f, -0.329f, -0.0f, -0.651f, 0.525f, 0.528f,
+ -0.327f, -0.0f, -0.637f, 0.528f, 0.53f, -0.325f, -0.0f, -0.624f, 0.53f, 0.532f, -0.322f, -0.0f, -0.61f, 0.532f, 0.534f, -0.319f, -0.0f, -0.597f, 0.535f, 0.535f,
+ -0.316f, -0.0f, -0.584f, 0.537f, 0.538f, -0.313f, -0.0f, -0.57f, 0.539f, 0.54f, -0.31f, -0.0f, -0.557f, 0.541f, 0.542f, -0.307f, -0.0f, -0.544f, 0.542f, 0.545f,
+ -0.303f, -0.0f, -0.531f, 0.544f, 0.546f, -0.3f, -0.0f, -0.519f, 0.546f, 0.549f, -0.298f, -0.0f, -0.506f, 0.547f, 0.549f, -0.295f, -0.0f, -0.494f, 0.548f, 0.549f,
+ -0.292f, -0.0f, -0.482f, 0.549f, 0.55f, -0.29f, -0.0f, -0.47f, 0.55f, 0.552f, -0.287f, -0.0f, -0.459f, 0.551f, 0.552f, -0.285f, -0.0f, -0.447f, 0.551f, 0.552f,
+ -0.284f, -0.0f, -0.436f, 0.552f, 0.552f, -0.282f, -0.0f, -0.425f, 0.552f, 0.553f, -0.281f, -0.0f, -0.413f, 0.553f, 0.553f, -0.28f, -0.0f, -0.402f, 0.553f, 0.553f,
+ -0.28f, -0.0f, -0.392f, 0.553f, 0.553f, -0.281f, -0.0f, -0.381f, 0.554f, 0.553f, -0.283f, -0.0f, -0.369f, 0.554f, 0.554f, -0.286f, -0.0f, -0.359f, 0.554f, 0.554f,
+ -0.289f, -0.0f, -0.348f, 0.555f, 0.554f, -0.294f, -0.0f, -0.337f, 0.555f, 0.555f, -0.299f, -0.0f, -0.327f, 0.555f, 0.554f, -0.305f, -0.0f, -0.317f, 0.556f, 0.555f,
+ -0.312f, -0.0f, -0.307f, 0.556f, 0.555f, -0.319f, -0.0f, -0.297f, 0.556f, 0.557f, -0.326f, 0.0f, -0.287f, 0.557f, 0.558f, -0.334f, 0.0f, -0.278f, 0.557f, 0.557f,
+ -0.341f, 0.0f, -0.268f, 0.557f, 0.558f, -0.349f, 0.0f, -0.259f, 0.558f, 0.558f, -0.359f, 0.0f, -0.251f, 0.558f, 0.558f, -0.368f, 0.0f, -0.243f, 0.558f, 0.558f,
+ -0.378f, 0.0f, -0.235f, 0.558f, 0.559f, -0.388f, 0.0f, -0.228f, 0.558f, 0.558f, -0.398f, 0.0f, -0.221f, 0.559f, 0.559f, -0.408f, 0.0f, -0.214f, 0.559f, 0.559f,
+ -0.418f, 0.0f, -0.208f, 0.559f, 0.559f, -0.427f, 0.0f, -0.202f, 0.559f, 0.558f, -0.436f, 0.0f, -0.196f, 0.559f, 0.559f, -0.445f, 0.0f, -0.191f, 0.559f, 0.559f,
+ -0.453f, 0.0f, -0.187f, 0.558f, 0.559f, -0.462f, 0.0f, -0.183f, 0.558f, 0.558f, -0.469f, 0.0f, -0.18f, 0.558f, 0.558f, -0.477f, 0.0f, -0.176f, 0.558f, 0.558f,
+ -0.484f, 0.0f, -0.174f, 0.557f, 0.558f, -0.493f, 0.0f, -0.17f, 0.555f, 0.559f,
+};
+
+
+static const float data1[136 * GP_PRIM_DATABUF_SIZE] = {
+ -0.369f, 0.0f, -0.048f, 0.065f, 0.065f, -0.378f, 0.0f, -0.046f, 0.239f, 0.293f, -0.383f, 0.0f, -0.044f, 0.316f, 0.339f, -0.39f, 0.0f, -0.041f, 0.348f, 0.355f,
+ -0.398f, 0.0f, -0.038f, 0.364f, 0.368f, -0.405f, 0.0f, -0.035f, 0.373f, 0.374f, -0.413f, 0.0f, -0.031f, 0.381f, 0.381f, -0.421f, 0.0f, -0.026f, 0.388f, 0.391f,
+ -0.429f, 0.0f, -0.02f, 0.392f, 0.394f, -0.437f, 0.0f, -0.014f, 0.395f, 0.396f, -0.445f, 0.0f, -0.008f, 0.397f, 0.397f, -0.453f, 0.0f, -0.001f, 0.399f, 0.4f,
+ -0.461f, 0.0f, 0.007f, 0.401f, 0.401f, -0.468f, -0.0f, 0.016f, 0.404f, 0.404f, -0.474f, 0.0f, 0.023f, 0.406f, 0.407f, -0.479f, 0.0f, 0.03f, 0.409f, 0.409f,
+ -0.485f, 0.0f, 0.039f, 0.412f, 0.412f, -0.49f, 0.0f, 0.048f, 0.415f, 0.415f, -0.495f, 0.0f, 0.057f, 0.417f, 0.417f, -0.499f, 0.0f, 0.068f, 0.42f, 0.421f,
+ -0.503f, 0.0f, 0.079f, 0.421f, 0.421f, -0.507f, -0.0f, 0.091f, 0.423f, 0.423f, -0.51f, -0.0f, 0.102f, 0.424f, 0.424f, -0.513f, -0.0f, 0.112f, 0.424f, 0.425f,
+ -0.515f, -0.0f, 0.123f, 0.425f, 0.425f, -0.517f, -0.0f, 0.135f, 0.425f, 0.425f, -0.518f, -0.0f, 0.146f, 0.426f, 0.425f, -0.519f, -0.0f, 0.158f, 0.426f, 0.425f,
+ -0.52f, -0.0f, 0.169f, 0.426f, 0.426f, -0.52f, -0.0f, 0.181f, 0.427f, 0.427f, -0.519f, -0.0f, 0.192f, 0.427f, 0.427f, -0.518f, -0.0f, 0.203f, 0.427f, 0.427f,
+ -0.517f, -0.0f, 0.213f, 0.427f, 0.428f, -0.515f, -0.0f, 0.222f, 0.428f, 0.427f, -0.513f, -0.0f, 0.232f, 0.428f, 0.427f, -0.51f, -0.0f, 0.241f, 0.429f, 0.427f,
+ -0.508f, -0.0f, 0.25f, 0.43f, 0.428f, -0.505f, -0.0f, 0.259f, 0.431f, 0.431f, -0.501f, -0.0f, 0.267f, 0.431f, 0.432f, -0.497f, -0.0f, 0.276f, 0.432f, 0.433f,
+ -0.493f, -0.0f, 0.284f, 0.433f, 0.433f, -0.488f, -0.0f, 0.293f, 0.434f, 0.434f, -0.484f, -0.0f, 0.301f, 0.434f, 0.435f, -0.479f, -0.0f, 0.308f, 0.435f, 0.436f,
+ -0.474f, -0.0f, 0.316f, 0.435f, 0.435f, -0.468f, -0.0f, 0.322f, 0.436f, 0.436f, -0.463f, -0.0f, 0.329f, 0.436f, 0.436f, -0.457f, -0.0f, 0.335f, 0.436f, 0.436f,
+ -0.451f, -0.0f, 0.341f, 0.437f, 0.436f, -0.445f, -0.0f, 0.347f, 0.438f, 0.437f, -0.438f, -0.0f, 0.352f, 0.44f, 0.437f, -0.432f, -0.0f, 0.357f, 0.442f, 0.441f,
+ -0.426f, 0.0f, 0.362f, 0.444f, 0.446f, -0.419f, 0.0f, 0.366f, 0.445f, 0.447f, -0.413f, 0.0f, 0.369f, 0.446f, 0.447f, -0.407f, 0.0f, 0.373f, 0.446f, 0.447f,
+ -0.401f, 0.0f, 0.376f, 0.447f, 0.447f, -0.395f, 0.0f, 0.378f, 0.447f, 0.448f, -0.388f, 0.0f, 0.381f, 0.447f, 0.448f, -0.382f, 0.0f, 0.383f, 0.448f, 0.448f,
+ -0.375f, 0.0f, 0.384f, 0.448f, 0.448f, -0.369f, 0.0f, 0.386f, 0.448f, 0.448f, -0.362f, 0.0f, 0.387f, 0.448f, 0.448f, -0.355f, 0.0f, 0.388f, 0.448f, 0.448f,
+ -0.348f, 0.0f, 0.388f, 0.448f, 0.448f, -0.341f, 0.0f, 0.387f, 0.448f, 0.449f, -0.334f, 0.0f, 0.387f, 0.448f, 0.448f, -0.327f, 0.0f, 0.386f, 0.448f, 0.449f,
+ -0.32f, 0.0f, 0.384f, 0.449f, 0.449f, -0.313f, 0.0f, 0.382f, 0.449f, 0.449f, -0.307f, 0.0f, 0.38f, 0.449f, 0.449f, -0.3f, 0.0f, 0.377f, 0.449f, 0.45f,
+ -0.294f, 0.0f, 0.375f, 0.45f, 0.45f, -0.288f, -0.0f, 0.372f, 0.45f, 0.45f, -0.282f, -0.0f, 0.368f, 0.45f, 0.451f, -0.276f, -0.0f, 0.365f, 0.45f, 0.451f,
+ -0.27f, -0.0f, 0.361f, 0.45f, 0.451f, -0.264f, -0.0f, 0.357f, 0.45f, 0.451f, -0.258f, -0.0f, 0.352f, 0.45f, 0.45f, -0.251f, -0.0f, 0.347f, 0.45f, 0.451f,
+ -0.245f, -0.0f, 0.341f, 0.451f, 0.451f, -0.24f, -0.0f, 0.335f, 0.451f, 0.451f, -0.234f, -0.0f, 0.329f, 0.451f, 0.451f, -0.228f, -0.0f, 0.323f, 0.452f, 0.452f,
+ -0.223f, -0.0f, 0.316f, 0.452f, 0.453f, -0.218f, -0.0f, 0.309f, 0.452f, 0.453f, -0.213f, -0.0f, 0.301f, 0.453f, 0.453f, -0.208f, -0.0f, 0.294f, 0.453f, 0.453f,
+ -0.204f, -0.0f, 0.286f, 0.453f, 0.453f, -0.2f, -0.0f, 0.277f, 0.453f, 0.454f, -0.196f, -0.0f, 0.269f, 0.453f, 0.454f, -0.192f, -0.0f, 0.26f, 0.454f, 0.454f,
+ -0.189f, -0.0f, 0.25f, 0.454f, 0.454f, -0.186f, -0.0f, 0.241f, 0.454f, 0.455f, -0.183f, -0.0f, 0.231f, 0.454f, 0.455f, -0.181f, -0.0f, 0.221f, 0.454f, 0.455f,
+ -0.179f, -0.0f, 0.209f, 0.455f, 0.455f, -0.177f, -0.0f, 0.197f, 0.455f, 0.455f, -0.176f, -0.0f, 0.184f, 0.455f, 0.455f, -0.176f, -0.0f, 0.171f, 0.455f, 0.456f,
+ -0.176f, -0.0f, 0.158f, 0.455f, 0.456f, -0.177f, -0.0f, 0.145f, 0.455f, 0.456f, -0.178f, -0.0f, 0.132f, 0.455f, 0.456f, -0.18f, -0.0f, 0.12f, 0.456f, 0.456f,
+ -0.182f, -0.0f, 0.108f, 0.456f, 0.456f, -0.185f, -0.0f, 0.097f, 0.456f, 0.456f, -0.188f, -0.0f, 0.086f, 0.456f, 0.457f, -0.191f, -0.0f, 0.076f, 0.456f, 0.457f,
+ -0.194f, -0.0f, 0.067f, 0.457f, 0.457f, -0.198f, -0.0f, 0.058f, 0.457f, 0.457f, -0.202f, -0.0f, 0.05f, 0.457f, 0.457f, -0.206f, -0.0f, 0.042f, 0.457f, 0.457f,
+ -0.21f, -0.0f, 0.034f, 0.458f, 0.457f, -0.215f, -0.0f, 0.027f, 0.458f, 0.457f, -0.22f, -0.0f, 0.02f, 0.458f, 0.458f, -0.225f, -0.0f, 0.014f, 0.458f, 0.458f,
+ -0.23f, -0.0f, 0.007f, 0.458f, 0.458f, -0.235f, -0.0f, 0.002f, 0.459f, 0.458f, -0.24f, -0.0f, -0.004f, 0.459f, 0.458f, -0.246f, -0.0f, -0.009f, 0.46f, 0.459f,
+ -0.251f, 0.0f, -0.013f, 0.464f, 0.463f, -0.257f, 0.0f, -0.018f, 0.467f, 0.468f, -0.262f, 0.0f, -0.022f, 0.469f, 0.469f, -0.268f, 0.0f, -0.026f, 0.471f, 0.47f,
+ -0.274f, 0.0f, -0.029f, 0.477f, 0.478f, -0.28f, 0.0f, -0.033f, 0.478f, 0.478f, -0.286f, 0.0f, -0.036f, 0.478f, 0.478f, -0.292f, 0.0f, -0.038f, 0.479f, 0.479f,
+ -0.298f, 0.0f, -0.041f, 0.48f, 0.48f, -0.305f, 0.0f, -0.043f, 0.48f, 0.48f, -0.311f, 0.0f, -0.045f, 0.482f, 0.482f, -0.318f, 0.0f, -0.047f, 0.482f, 0.482f,
+ -0.324f, 0.0f, -0.048f, 0.482f, 0.482f, -0.331f, 0.0f, -0.049f, 0.48f, 0.482f, -0.336f, 0.0f, -0.05f, 0.457f, 0.485f, -0.344f, 0.0f, -0.05f, 0.32f, 0.32f,
+};
+
+static const float data2[2 * GP_PRIM_DATABUF_SIZE] = {
+ -0.512f, 0.0f, -0.168f, 0.545f, 0.557f, -0.521f, 0.0f, -0.167f, 0.535f, 0.558f,
+};
+
+static const float data3[1 * GP_PRIM_DATABUF_SIZE] = {
+ -1.014f, 0.0f, 0.186f, 0.0f, 0.003f,
+};
+
+static const float data4[1 * GP_PRIM_DATABUF_SIZE] = {
+ -1.014f, 0.0f, 0.186f, 0.02f, 0.02f,
+};
+
+static const float data5[48 * GP_PRIM_DATABUF_SIZE] = {
+ -1.014f, 0.0f, 0.187f, 0.066f, 0.066f, -1.013f, 0.0f, 0.2f, 0.222f, 0.356f, -1.01f, 0.0f, 0.208f, 0.295f, 0.404f, -1.006f, 0.0f, 0.218f, 0.354f, 0.431f,
+ -1.001f, 0.0f, 0.226f, 0.392f, 0.445f, -0.994f, 0.0f, 0.233f, 0.418f, 0.453f, -0.987f, 0.0f, 0.238f, 0.437f, 0.457f, -0.979f, 0.0f, 0.242f, 0.45f, 0.47f,
+ -0.97f, 0.0f, 0.245f, 0.459f, 0.473f, -0.96f, -0.0f, 0.246f, 0.465f, 0.474f, -0.951f, -0.0f, 0.245f, 0.469f, 0.475f, -0.942f, 0.0f, 0.242f, 0.471f, 0.473f,
+ -0.932f, 0.0f, 0.239f, 0.472f, 0.474f, -0.924f, 0.0f, 0.234f, 0.471f, 0.474f, -0.915f, 0.0f, 0.228f, 0.469f, 0.474f, -0.906f, 0.0f, 0.22f, 0.464f, 0.47f,
+ -0.898f, 0.0f, 0.212f, 0.458f, 0.46f, -0.89f, 0.0f, 0.203f, 0.451f, 0.453f, -0.882f, 0.0f, 0.193f, 0.443f, 0.443f, -0.875f, 0.0f, 0.182f, 0.435f, 0.437f,
+ -0.869f, 0.0f, 0.172f, 0.426f, 0.428f, -0.863f, 0.0f, 0.161f, 0.417f, 0.415f, -0.858f, 0.0f, 0.148f, 0.409f, 0.41f, -0.854f, 0.0f, 0.137f, 0.399f, 0.399f,
+ -0.85f, 0.0f, 0.126f, 0.39f, 0.392f, -0.847f, 0.0f, 0.116f, 0.379f, 0.386f, -0.846f, 0.0f, 0.109f, 0.369f, 0.371f, -0.846f, 0.0f, 0.104f, 0.361f, 0.357f,
+ -0.847f, 0.0f, 0.101f, 0.355f, 0.339f, -0.849f, 0.0f, 0.101f, 0.353f, 0.334f, -0.853f, 0.0f, 0.103f, 0.354f, 0.345f, -0.859f, 0.0f, 0.108f, 0.357f, 0.35f,
+ -0.865f, 0.0f, 0.116f, 0.363f, 0.365f, -0.873f, 0.0f, 0.126f, 0.369f, 0.375f, -0.881f, 0.0f, 0.137f, 0.375f, 0.379f, -0.89f, 0.0f, 0.149f, 0.381f, 0.38f,
+ -0.899f, 0.0f, 0.159f, 0.387f, 0.385f, -0.908f, 0.0f, 0.168f, 0.394f, 0.394f, -0.919f, 0.0f, 0.177f, 0.401f, 0.398f, -0.932f, 0.0f, 0.184f, 0.409f, 0.404f,
+ -0.945f, 0.0f, 0.191f, 0.418f, 0.415f, -0.958f, 0.0f, 0.195f, 0.427f, 0.431f, -0.969f, 0.0f, 0.197f, 0.434f, 0.443f, -0.979f, 0.0f, 0.197f, 0.436f, 0.445f,
+ -0.987f, 0.0f, 0.195f, 0.428f, 0.463f, -0.995f, 0.0f, 0.192f, 0.398f, 0.46f, -1.001f, 0.0f, 0.189f, 0.345f, 0.465f, -1.01f, 0.0f, 0.183f, 0.236f, 0.236f,
+};
+
+static const float data6[47 * GP_PRIM_DATABUF_SIZE] = {
+ 0.022f, 0.0f, -0.353f, 0.125f, 0.125f, 0.012f, 0.0f, -0.352f, 0.175f, 0.288f, 0.004f, 0.0f, -0.352f, 0.206f, 0.313f, -0.006f, 0.0f, -0.352f, 0.241f, 0.323f,
+ -0.017f, 0.0f, -0.352f, 0.27f, 0.33f, -0.029f, 0.0f, -0.351f, 0.295f, 0.334f, -0.041f, 0.0f, -0.349f, 0.314f, 0.337f, -0.052f, 0.0f, -0.344f, 0.327f, 0.341f,
+ -0.063f, 0.0f, -0.337f, 0.336f, 0.344f, -0.072f, 0.0f, -0.329f, 0.341f, 0.345f, -0.081f, 0.0f, -0.32f, 0.345f, 0.345f, -0.088f, 0.0f, -0.311f, 0.348f, 0.345f,
+ -0.093f, 0.0f, -0.303f, 0.352f, 0.347f, -0.098f, 0.0f, -0.295f, 0.356f, 0.352f, -0.101f, 0.0f, -0.287f, 0.361f, 0.357f, -0.102f, 0.0f, -0.279f, 0.367f, 0.364f,
+ -0.103f, 0.0f, -0.271f, 0.373f, 0.378f, -0.102f, 0.0f, -0.263f, 0.379f, 0.382f, -0.1f, 0.0f, -0.255f, 0.383f, 0.389f, -0.098f, 0.0f, -0.247f, 0.387f, 0.391f,
+ -0.094f, 0.0f, -0.24f, 0.389f, 0.393f, -0.09f, 0.0f, -0.233f, 0.391f, 0.393f, -0.086f, 0.0f, -0.227f, 0.392f, 0.393f, -0.082f, 0.0f, -0.222f, 0.393f, 0.393f,
+ -0.078f, 0.0f, -0.219f, 0.394f, 0.393f, -0.075f, 0.0f, -0.217f, 0.397f, 0.393f, -0.072f, 0.0f, -0.217f, 0.4f, 0.393f, -0.07f, 0.0f, -0.219f, 0.402f, 0.408f,
+ -0.069f, 0.0f, -0.222f, 0.404f, 0.408f, -0.069f, 0.0f, -0.228f, 0.406f, 0.409f, -0.069f, 0.0f, -0.234f, 0.407f, 0.409f, -0.07f, 0.0f, -0.241f, 0.408f, 0.409f,
+ -0.07f, 0.0f, -0.248f, 0.408f, 0.409f, -0.07f, 0.0f, -0.256f, 0.409f, 0.409f, -0.07f, 0.0f, -0.263f, 0.409f, 0.41f, -0.069f, 0.0f, -0.271f, 0.41f, 0.411f,
+ -0.068f, 0.0f, -0.279f, 0.41f, 0.411f, -0.065f, 0.0f, -0.287f, 0.41f, 0.411f, -0.062f, 0.0f, -0.295f, 0.409f, 0.411f, -0.057f, 0.0f, -0.303f, 0.409f, 0.409f,
+ -0.052f, 0.0f, -0.31f, 0.408f, 0.409f, -0.047f, 0.0f, -0.318f, 0.407f, 0.408f, -0.041f, 0.0f, -0.324f, 0.406f, 0.407f, -0.035f, 0.0f, -0.329f, 0.403f, 0.407f,
+ -0.027f, 0.0f, -0.333f, 0.4f, 0.408f, -0.021f, 0.0f, -0.336f, 0.398f, 0.403f, -0.012f, 0.0f, -0.339f, 0.393f, 0.393f,
+};
+
+static const float data7[162 * GP_PRIM_DATABUF_SIZE] = {
+ -0.291f, 0.0f, -0.34f, 0.093f, 0.093f, -0.289f, -0.0f, -0.35f, 0.149f, 0.176f, -0.287f, -0.0f, -0.357f, 0.182f, 0.242f, -0.284f, -0.0f, -0.365f, 0.215f, 0.257f,
+ -0.281f, -0.0f, -0.374f, 0.242f, 0.266f, -0.278f, -0.0f, -0.384f, 0.266f, 0.287f, -0.275f, -0.0f, -0.394f, 0.285f, 0.304f, -0.271f, 0.0f, -0.405f, 0.302f, 0.316f,
+ -0.267f, 0.0f, -0.417f, 0.317f, 0.326f, -0.263f, 0.0f, -0.429f, 0.33f, 0.337f, -0.259f, 0.0f, -0.442f, 0.342f, 0.346f, -0.256f, 0.0f, -0.454f, 0.354f, 0.351f,
+ -0.253f, 0.0f, -0.467f, 0.365f, 0.362f, -0.251f, 0.0f, -0.48f, 0.376f, 0.38f, -0.249f, -0.0f, -0.493f, 0.386f, 0.391f, -0.247f, -0.0f, -0.505f, 0.394f, 0.396f,
+ -0.246f, -0.0f, -0.518f, 0.401f, 0.405f, -0.245f, 0.0f, -0.53f, 0.408f, 0.409f, -0.245f, 0.0f, -0.542f, 0.415f, 0.413f, -0.245f, 0.0f, -0.554f, 0.421f, 0.42f,
+ -0.245f, 0.0f, -0.565f, 0.426f, 0.43f, -0.246f, 0.0f, -0.575f, 0.43f, 0.433f, -0.246f, -0.0f, -0.585f, 0.432f, 0.435f, -0.247f, -0.0f, -0.594f, 0.434f, 0.436f,
+ -0.247f, -0.0f, -0.603f, 0.435f, 0.436f, -0.248f, -0.0f, -0.612f, 0.436f, 0.436f, -0.25f, -0.0f, -0.621f, 0.437f, 0.438f, -0.252f, -0.0f, -0.631f, 0.437f, 0.438f,
+ -0.254f, -0.0f, -0.642f, 0.438f, 0.438f, -0.255f, 0.0f, -0.653f, 0.438f, 0.438f, -0.258f, 0.0f, -0.664f, 0.438f, 0.439f, -0.26f, 0.0f, -0.674f, 0.439f, 0.439f,
+ -0.261f, 0.0f, -0.685f, 0.439f, 0.439f, -0.262f, 0.0f, -0.696f, 0.439f, 0.439f, -0.264f, 0.0f, -0.706f, 0.439f, 0.439f, -0.265f, 0.0f, -0.717f, 0.439f, 0.439f,
+ -0.265f, 0.0f, -0.727f, 0.438f, 0.439f, -0.266f, 0.0f, -0.738f, 0.437f, 0.439f, -0.266f, 0.0f, -0.749f, 0.435f, 0.438f, -0.266f, 0.0f, -0.76f, 0.433f, 0.433f,
+ -0.265f, 0.0f, -0.771f, 0.431f, 0.428f, -0.265f, 0.0f, -0.781f, 0.43f, 0.428f, -0.263f, 0.0f, -0.792f, 0.429f, 0.428f, -0.26f, 0.0f, -0.802f, 0.428f, 0.429f,
+ -0.257f, 0.0f, -0.812f, 0.426f, 0.427f, -0.254f, 0.0f, -0.821f, 0.423f, 0.426f, -0.25f, 0.0f, -0.829f, 0.421f, 0.42f, -0.247f, 0.0f, -0.837f, 0.418f, 0.416f,
+ -0.242f, 0.0f, -0.844f, 0.417f, 0.415f, -0.238f, 0.0f, -0.85f, 0.415f, 0.413f, -0.234f, 0.0f, -0.857f, 0.415f, 0.413f, -0.229f, 0.0f, -0.864f, 0.414f, 0.413f,
+ -0.224f, 0.0f, -0.87f, 0.414f, 0.413f, -0.219f, 0.0f, -0.877f, 0.414f, 0.414f, -0.214f, 0.0f, -0.883f, 0.414f, 0.413f, -0.208f, 0.0f, -0.89f, 0.413f, 0.413f,
+ -0.203f, 0.0f, -0.897f, 0.413f, 0.413f, -0.197f, 0.0f, -0.903f, 0.413f, 0.413f, -0.191f, 0.0f, -0.909f, 0.413f, 0.413f, -0.186f, 0.0f, -0.914f, 0.413f, 0.413f,
+ -0.181f, 0.0f, -0.92f, 0.413f, 0.413f, -0.175f, -0.0f, -0.925f, 0.413f, 0.413f, -0.17f, -0.0f, -0.931f, 0.413f, 0.413f, -0.164f, -0.0f, -0.936f, 0.413f, 0.413f,
+ -0.159f, -0.0f, -0.942f, 0.413f, 0.413f, -0.152f, -0.0f, -0.948f, 0.413f, 0.413f, -0.145f, -0.0f, -0.955f, 0.413f, 0.413f, -0.137f, -0.0f, -0.961f, 0.414f, 0.413f,
+ -0.13f, -0.0f, -0.967f, 0.414f, 0.413f, -0.122f, -0.0f, -0.974f, 0.414f, 0.414f, -0.114f, -0.0f, -0.979f, 0.414f, 0.413f, -0.106f, -0.0f, -0.985f, 0.414f, 0.413f,
+ -0.098f, -0.0f, -0.989f, 0.414f, 0.414f, -0.091f, -0.0f, -0.993f, 0.414f, 0.413f, -0.083f, -0.0f, -0.997f, 0.414f, 0.414f, -0.075f, -0.0f, -0.999f, 0.414f, 0.414f,
+ -0.066f, -0.0f, -1.001f, 0.414f, 0.414f, -0.057f, -0.0f, -1.003f, 0.414f, 0.413f, -0.046f, -0.0f, -1.006f, 0.414f, 0.413f, -0.038f, -0.0f, -1.008f, 0.414f, 0.413f,
+ -0.031f, -0.0f, -1.009f, 0.421f, 0.413f, -0.036f, -0.0f, -1.008f, 0.423f, 0.424f, -0.045f, -0.0f, -1.006f, 0.425f, 0.425f, -0.054f, -0.0f, -1.005f, 0.425f, 0.425f,
+ -0.064f, -0.0f, -1.005f, 0.425f, 0.425f, -0.073f, -0.0f, -1.004f, 0.425f, 0.425f, -0.084f, -0.0f, -1.003f, 0.425f, 0.425f, -0.095f, -0.0f, -1.001f, 0.424f, 0.424f,
+ -0.105f, -0.0f, -0.997f, 0.423f, 0.424f, -0.116f, -0.0f, -0.994f, 0.422f, 0.422f, -0.127f, -0.0f, -0.991f, 0.421f, 0.419f, -0.137f, -0.0f, -0.987f, 0.42f, 0.419f,
+ -0.148f, -0.0f, -0.983f, 0.42f, 0.419f, -0.158f, -0.0f, -0.98f, 0.42f, 0.419f, -0.167f, -0.0f, -0.976f, 0.419f, 0.419f, -0.176f, -0.0f, -0.973f, 0.419f, 0.419f,
+ -0.184f, -0.0f, -0.969f, 0.419f, 0.419f, -0.192f, -0.0f, -0.966f, 0.419f, 0.418f, -0.2f, 0.0f, -0.962f, 0.419f, 0.418f, -0.207f, 0.0f, -0.957f, 0.419f, 0.419f,
+ -0.215f, 0.0f, -0.953f, 0.419f, 0.418f, -0.223f, 0.0f, -0.948f, 0.419f, 0.419f, -0.231f, 0.0f, -0.944f, 0.419f, 0.419f, -0.239f, 0.0f, -0.939f, 0.419f, 0.419f,
+ -0.247f, 0.0f, -0.934f, 0.419f, 0.419f, -0.255f, 0.0f, -0.929f, 0.419f, 0.419f, -0.262f, 0.0f, -0.924f, 0.419f, 0.419f, -0.269f, 0.0f, -0.919f, 0.419f, 0.418f,
+ -0.275f, 0.0f, -0.914f, 0.419f, 0.419f, -0.281f, 0.0f, -0.909f, 0.419f, 0.418f, -0.287f, 0.0f, -0.904f, 0.419f, 0.418f, -0.293f, 0.0f, -0.899f, 0.419f, 0.418f,
+ -0.299f, 0.0f, -0.894f, 0.42f, 0.419f, -0.304f, 0.0f, -0.888f, 0.421f, 0.42f, -0.311f, 0.0f, -0.882f, 0.423f, 0.422f, -0.317f, 0.0f, -0.876f, 0.424f, 0.424f,
+ -0.322f, 0.0f, -0.869f, 0.426f, 0.426f, -0.328f, 0.0f, -0.861f, 0.427f, 0.427f, -0.332f, 0.0f, -0.853f, 0.429f, 0.429f, -0.336f, 0.0f, -0.843f, 0.43f, 0.429f,
+ -0.339f, 0.0f, -0.834f, 0.432f, 0.431f, -0.341f, 0.0f, -0.821f, 0.435f, 0.434f, -0.342f, 0.0f, -0.809f, 0.438f, 0.439f, -0.343f, 0.0f, -0.796f, 0.44f, 0.44f,
+ -0.343f, 0.0f, -0.783f, 0.442f, 0.442f, -0.343f, 0.0f, -0.772f, 0.446f, 0.445f, -0.342f, 0.0f, -0.76f, 0.45f, 0.45f, -0.342f, 0.0f, -0.748f, 0.454f, 0.455f,
+ -0.34f, 0.0f, -0.735f, 0.457f, 0.457f, -0.339f, 0.0f, -0.723f, 0.46f, 0.46f, -0.338f, 0.0f, -0.711f, 0.463f, 0.464f, -0.336f, 0.0f, -0.7f, 0.465f, 0.465f,
+ -0.335f, 0.0f, -0.688f, 0.466f, 0.466f, -0.332f, 0.0f, -0.676f, 0.467f, 0.467f, -0.331f, 0.0f, -0.664f, 0.467f, 0.467f, -0.33f, 0.0f, -0.651f, 0.467f, 0.467f,
+ -0.328f, 0.0f, -0.638f, 0.467f, 0.467f, -0.325f, 0.0f, -0.625f, 0.467f, 0.467f, -0.323f, 0.0f, -0.614f, 0.467f, 0.467f, -0.321f, 0.0f, -0.603f, 0.467f, 0.466f,
+ -0.318f, 0.0f, -0.592f, 0.467f, 0.466f, -0.315f, 0.0f, -0.581f, 0.467f, 0.466f, -0.313f, 0.0f, -0.569f, 0.467f, 0.467f, -0.311f, -0.0f, -0.557f, 0.467f, 0.467f,
+ -0.309f, -0.0f, -0.543f, 0.467f, 0.467f, -0.306f, -0.0f, -0.531f, 0.467f, 0.467f, -0.303f, -0.0f, -0.519f, 0.467f, 0.467f, -0.301f, -0.0f, -0.507f, 0.467f, 0.468f,
+ -0.299f, -0.0f, -0.497f, 0.467f, 0.467f, -0.297f, -0.0f, -0.487f, 0.467f, 0.467f, -0.295f, 0.0f, -0.476f, 0.465f, 0.467f, -0.293f, 0.0f, -0.466f, 0.463f, 0.467f,
+ -0.292f, 0.0f, -0.456f, 0.46f, 0.466f, -0.291f, 0.0f, -0.445f, 0.455f, 0.459f, -0.29f, 0.0f, -0.435f, 0.449f, 0.457f, -0.29f, 0.0f, -0.424f, 0.44f, 0.448f,
+ -0.29f, 0.0f, -0.413f, 0.43f, 0.44f, -0.29f, 0.0f, -0.403f, 0.418f, 0.437f, -0.29f, -0.0f, -0.393f, 0.404f, 0.415f, -0.291f, -0.0f, -0.384f, 0.388f, 0.393f,
+ -0.29f, -0.0f, -0.376f, 0.374f, 0.379f, -0.29f, -0.0f, -0.365f, 0.352f, 0.352f,
+};
+
+static const float data8[55 * GP_PRIM_DATABUF_SIZE] = {
+ 0.781f, 0.0f, 0.098f, 0.109f, 0.109f, 0.784f, 0.0f, 0.105f, 0.202f, 0.338f, 0.785f, 0.0f, 0.108f, 0.254f, 0.369f, 0.787f, 0.0f, 0.113f, 0.306f, 0.382f,
+ 0.787f, 0.0f, 0.118f, 0.344f, 0.392f, 0.789f, 0.0f, 0.123f, 0.372f, 0.401f, 0.79f, 0.0f, 0.128f, 0.392f, 0.41f, 0.792f, 0.0f, 0.135f, 0.406f, 0.42f,
+ 0.794f, 0.0f, 0.142f, 0.416f, 0.424f, 0.797f, 0.0f, 0.152f, 0.424f, 0.428f, 0.801f, 0.0f, 0.161f, 0.429f, 0.431f, 0.807f, 0.0f, 0.172f, 0.432f, 0.435f,
+ 0.814f, 0.0f, 0.182f, 0.435f, 0.438f, 0.821f, 0.0f, 0.19f, 0.437f, 0.439f, 0.828f, 0.0f, 0.197f, 0.439f, 0.44f, 0.836f, 0.0f, 0.204f, 0.44f, 0.441f,
+ 0.845f, -0.0f, 0.211f, 0.44f, 0.441f, 0.853f, -0.0f, 0.215f, 0.441f, 0.441f, 0.861f, -0.0f, 0.219f, 0.441f, 0.441f, 0.87f, -0.0f, 0.222f, 0.441f, 0.442f,
+ 0.878f, -0.0f, 0.224f, 0.441f, 0.442f, 0.886f, -0.0f, 0.226f, 0.441f, 0.442f, 0.895f, -0.0f, 0.227f, 0.44f, 0.442f, 0.903f, 0.0f, 0.226f, 0.439f, 0.441f,
+ 0.911f, 0.0f, 0.225f, 0.436f, 0.441f, 0.919f, 0.0f, 0.224f, 0.432f, 0.441f, 0.927f, 0.0f, 0.221f, 0.425f, 0.436f, 0.934f, 0.0f, 0.218f, 0.415f, 0.429f,
+ 0.94f, 0.0f, 0.215f, 0.404f, 0.406f, 0.944f, 0.0f, 0.211f, 0.393f, 0.389f, 0.947f, 0.0f, 0.208f, 0.384f, 0.378f, 0.948f, 0.0f, 0.204f, 0.376f, 0.371f,
+ 0.946f, 0.0f, 0.2f, 0.369f, 0.364f, 0.943f, 0.0f, 0.196f, 0.365f, 0.358f, 0.937f, 0.0f, 0.193f, 0.364f, 0.354f, 0.931f, 0.0f, 0.189f, 0.366f, 0.359f,
+ 0.925f, 0.0f, 0.186f, 0.37f, 0.367f, 0.917f, 0.0f, 0.182f, 0.374f, 0.375f, 0.908f, 0.0f, 0.177f, 0.378f, 0.382f, 0.899f, 0.0f, 0.172f, 0.381f, 0.384f,
+ 0.889f, 0.0f, 0.167f, 0.384f, 0.385f, 0.876f, 0.0f, 0.163f, 0.387f, 0.387f, 0.864f, 0.0f, 0.156f, 0.39f, 0.388f, 0.852f, 0.0f, 0.15f, 0.393f, 0.39f,
+ 0.841f, 0.0f, 0.144f, 0.396f, 0.396f, 0.832f, 0.0f, 0.138f, 0.399f, 0.401f, 0.826f, 0.0f, 0.133f, 0.401f, 0.404f, 0.82f, 0.0f, 0.127f, 0.403f, 0.405f,
+ 0.816f, 0.0f, 0.122f, 0.403f, 0.407f, 0.812f, 0.0f, 0.119f, 0.399f, 0.406f, 0.808f, 0.0f, 0.115f, 0.39f, 0.405f, 0.805f, 0.0f, 0.113f, 0.371f, 0.407f,
+ 0.801f, 0.0f, 0.111f, 0.341f, 0.407f, 0.799f, 0.0f, 0.109f, 0.309f, 0.405f, 0.795f, 0.0f, 0.106f, 0.255f, 0.255f,
+};
+
+static const float data9[70 * GP_PRIM_DATABUF_SIZE] = {
+ 0.819f, -0.0f, 0.325f, 0.109f, 0.109f, 0.829f, -0.0f, 0.328f, 0.258f, 0.403f, 0.835f, -0.0f, 0.329f, 0.327f, 0.428f, 0.843f, -0.0f, 0.331f, 0.383f, 0.452f,
+ 0.851f, -0.0f, 0.332f, 0.419f, 0.465f, 0.861f, -0.0f, 0.334f, 0.444f, 0.473f, 0.87f, -0.0f, 0.336f, 0.461f, 0.48f, 0.881f, -0.0f, 0.337f, 0.473f, 0.486f,
+ 0.892f, -0.0f, 0.339f, 0.482f, 0.496f, 0.904f, -0.0f, 0.341f, 0.489f, 0.501f, 0.917f, -0.0f, 0.342f, 0.494f, 0.503f, 0.931f, -0.0f, 0.342f, 0.498f, 0.505f,
+ 0.945f, -0.0f, 0.342f, 0.501f, 0.505f, 0.958f, -0.0f, 0.342f, 0.503f, 0.506f, 0.971f, -0.0f, 0.341f, 0.505f, 0.506f, 0.984f, -0.0f, 0.341f, 0.506f, 0.506f,
+ 0.997f, -0.0f, 0.339f, 0.507f, 0.508f, 1.009f, -0.0f, 0.337f, 0.507f, 0.507f, 1.021f, -0.0f, 0.333f, 0.508f, 0.508f, 1.033f, -0.0f, 0.33f, 0.508f, 0.508f,
+ 1.044f, -0.0f, 0.326f, 0.508f, 0.508f, 1.056f, -0.0f, 0.322f, 0.508f, 0.508f, 1.068f, -0.0f, 0.317f, 0.508f, 0.508f, 1.078f, -0.0f, 0.311f, 0.507f, 0.508f,
+ 1.089f, -0.0f, 0.304f, 0.506f, 0.508f, 1.099f, 0.0f, 0.294f, 0.503f, 0.506f, 1.107f, 0.0f, 0.287f, 0.498f, 0.506f, 1.113f, 0.0f, 0.28f, 0.49f, 0.505f,
+ 1.117f, 0.0f, 0.276f, 0.48f, 0.501f, 1.121f, 0.0f, 0.272f, 0.468f, 0.492f, 1.124f, 0.0f, 0.27f, 0.455f, 0.467f, 1.127f, 0.0f, 0.27f, 0.443f, 0.431f,
+ 1.129f, 0.0f, 0.271f, 0.431f, 0.4f, 1.13f, 0.0f, 0.274f, 0.422f, 0.399f, 1.13f, 0.0f, 0.278f, 0.414f, 0.399f, 1.13f, 0.0f, 0.286f, 0.408f, 0.399f,
+ 1.128f, 0.0f, 0.295f, 0.404f, 0.399f, 1.124f, 0.0f, 0.305f, 0.402f, 0.399f, 1.119f, 0.0f, 0.316f, 0.403f, 0.4f, 1.113f, -0.0f, 0.327f, 0.405f, 0.401f,
+ 1.107f, -0.0f, 0.337f, 0.408f, 0.411f, 1.1f, -0.0f, 0.345f, 0.412f, 0.412f, 1.094f, -0.0f, 0.352f, 0.416f, 0.413f, 1.087f, -0.0f, 0.357f, 0.421f, 0.422f,
+ 1.08f, -0.0f, 0.363f, 0.426f, 0.428f, 1.071f, -0.0f, 0.368f, 0.429f, 0.43f, 1.062f, -0.0f, 0.373f, 0.431f, 0.431f, 1.051f, -0.0f, 0.377f, 0.433f, 0.431f,
+ 1.039f, -0.0f, 0.381f, 0.436f, 0.437f, 1.026f, -0.0f, 0.383f, 0.438f, 0.44f, 1.013f, -0.0f, 0.384f, 0.44f, 0.44f, 1.0f, -0.0f, 0.385f, 0.441f, 0.443f,
+ 0.987f, -0.0f, 0.385f, 0.442f, 0.443f, 0.975f, -0.0f, 0.384f, 0.443f, 0.443f, 0.962f, -0.0f, 0.383f, 0.443f, 0.444f, 0.949f, -0.0f, 0.381f, 0.443f, 0.443f,
+ 0.936f, -0.0f, 0.38f, 0.443f, 0.444f, 0.923f, -0.0f, 0.378f, 0.443f, 0.444f, 0.909f, -0.0f, 0.375f, 0.443f, 0.444f, 0.897f, -0.0f, 0.371f, 0.443f, 0.444f,
+ 0.886f, -0.0f, 0.367f, 0.443f, 0.443f, 0.876f, -0.0f, 0.363f, 0.443f, 0.444f, 0.868f, -0.0f, 0.359f, 0.443f, 0.442f, 0.86f, -0.0f, 0.355f, 0.442f, 0.443f,
+ 0.852f, -0.0f, 0.35f, 0.441f, 0.443f, 0.844f, -0.0f, 0.347f, 0.433f, 0.443f, 0.837f, -0.0f, 0.343f, 0.409f, 0.443f, 0.83f, -0.0f, 0.338f, 0.344f, 0.443f,
+ 0.824f, -0.0f, 0.335f, 0.239f, 0.437f, 0.815f, -0.0f, 0.326f, 0.0f, 0.003f,
+};
+
+static const float data10[227 * GP_PRIM_DATABUF_SIZE] = {
+ -0.675f, 0.0f, 0.411f, 0.099f, 0.099f, -0.669f, 0.0f, 0.418f, 0.358f, 0.358f, -0.666f, 0.0f, 0.424f, 0.381f, 0.381f, -0.662f, 0.0f, 0.431f, 0.389f, 0.389f,
+ -0.658f, 0.0f, 0.438f, 0.393f, 0.393f, -0.649f, 0.0f, 0.448f, 0.404f, 0.404f, -0.641f, 0.0f, 0.458f, 0.419f, 0.419f, -0.632f, 0.0f, 0.468f, 0.431f, 0.434f,
+ -0.626f, 0.0f, 0.476f, 0.435f, 0.436f, -0.62f, 0.0f, 0.484f, 0.437f, 0.438f, -0.615f, 0.0f, 0.492f, 0.439f, 0.439f, -0.61f, 0.0f, 0.499f, 0.439f, 0.44f,
+ -0.605f, 0.0f, 0.506f, 0.44f, 0.44f, -0.6f, 0.0f, 0.512f, 0.44f, 0.44f, -0.595f, 0.0f, 0.519f, 0.44f, 0.44f, -0.59f, 0.0f, 0.526f, 0.441f, 0.441f,
+ -0.584f, 0.0f, 0.532f, 0.441f, 0.441f, -0.579f, 0.0f, 0.539f, 0.441f, 0.441f, -0.573f, 0.0f, 0.545f, 0.442f, 0.442f, -0.566f, 0.0f, 0.551f, 0.443f, 0.443f,
+ -0.559f, 0.0f, 0.557f, 0.443f, 0.443f, -0.552f, 0.0f, 0.563f, 0.444f, 0.444f, -0.545f, 0.0f, 0.569f, 0.445f, 0.445f, -0.538f, 0.0f, 0.576f, 0.447f, 0.447f,
+ -0.532f, 0.0f, 0.582f, 0.448f, 0.448f, -0.525f, 0.0f, 0.589f, 0.45f, 0.45f, -0.519f, 0.0f, 0.595f, 0.451f, 0.452f, -0.513f, 0.0f, 0.602f, 0.452f, 0.453f,
+ -0.506f, 0.0f, 0.608f, 0.453f, 0.453f, -0.5f, 0.0f, 0.613f, 0.453f, 0.454f, -0.493f, 0.0f, 0.619f, 0.453f, 0.454f, -0.486f, 0.0f, 0.625f, 0.453f, 0.454f,
+ -0.479f, 0.0f, 0.631f, 0.453f, 0.454f, -0.472f, 0.0f, 0.637f, 0.453f, 0.454f, -0.464f, 0.0f, 0.642f, 0.453f, 0.454f, -0.457f, 0.0f, 0.649f, 0.453f, 0.454f,
+ -0.45f, 0.0f, 0.655f, 0.453f, 0.453f, -0.443f, 0.0f, 0.661f, 0.453f, 0.453f, -0.435f, 0.0f, 0.667f, 0.453f, 0.454f, -0.427f, 0.0f, 0.672f, 0.453f, 0.454f,
+ -0.419f, 0.0f, 0.677f, 0.453f, 0.454f, -0.411f, 0.0f, 0.682f, 0.453f, 0.453f, -0.403f, 0.0f, 0.688f, 0.453f, 0.453f, -0.395f, 0.0f, 0.692f, 0.453f, 0.454f,
+ -0.387f, 0.0f, 0.697f, 0.453f, 0.454f, -0.379f, 0.0f, 0.702f, 0.453f, 0.454f, -0.372f, 0.0f, 0.707f, 0.454f, 0.454f, -0.364f, 0.0f, 0.712f, 0.454f, 0.454f,
+ -0.356f, 0.0f, 0.716f, 0.454f, 0.454f, -0.349f, 0.0f, 0.721f, 0.454f, 0.454f, -0.342f, 0.0f, 0.725f, 0.454f, 0.454f, -0.334f, 0.0f, 0.73f, 0.454f, 0.454f,
+ -0.326f, 0.0f, 0.733f, 0.454f, 0.454f, -0.318f, 0.0f, 0.737f, 0.454f, 0.454f, -0.31f, 0.0f, 0.74f, 0.454f, 0.454f, -0.301f, 0.0f, 0.743f, 0.454f, 0.454f,
+ -0.293f, 0.0f, 0.746f, 0.454f, 0.455f, -0.284f, 0.0f, 0.749f, 0.454f, 0.455f, -0.274f, 0.0f, 0.752f, 0.455f, 0.455f, -0.265f, 0.0f, 0.755f, 0.455f, 0.455f,
+ -0.255f, 0.0f, 0.757f, 0.455f, 0.455f, -0.245f, 0.0f, 0.76f, 0.456f, 0.455f, -0.234f, 0.0f, 0.762f, 0.457f, 0.456f, -0.223f, 0.0f, 0.764f, 0.458f, 0.458f,
+ -0.212f, 0.0f, 0.766f, 0.459f, 0.46f, -0.201f, 0.0f, 0.769f, 0.461f, 0.46f, -0.189f, 0.0f, 0.771f, 0.462f, 0.461f, -0.177f, 0.0f, 0.773f, 0.464f, 0.463f,
+ -0.166f, 0.0f, 0.775f, 0.465f, 0.465f, -0.153f, 0.0f, 0.777f, 0.467f, 0.467f, -0.141f, 0.0f, 0.779f, 0.469f, 0.469f, -0.128f, 0.0f, 0.781f, 0.472f, 0.472f,
+ -0.116f, 0.0f, 0.782f, 0.474f, 0.473f, -0.101f, 0.0f, 0.782f, 0.477f, 0.477f, -0.087f, 0.0f, 0.783f, 0.482f, 0.477f, -0.073f, 0.0f, 0.783f, 0.489f, 0.483f,
+ -0.059f, 0.0f, 0.783f, 0.497f, 0.5f, -0.046f, 0.0f, 0.784f, 0.503f, 0.509f, -0.033f, 0.0f, 0.784f, 0.508f, 0.51f, -0.022f, 0.0f, 0.784f, 0.51f, 0.512f,
+ -0.011f, 0.0f, 0.785f, 0.512f, 0.512f, -0.0f, 0.0f, 0.786f, 0.513f, 0.512f, 0.011f, 0.0f, 0.786f, 0.515f, 0.513f, 0.022f, 0.0f, 0.786f, 0.517f, 0.517f,
+ 0.032f, 0.0f, 0.786f, 0.52f, 0.519f, 0.044f, 0.0f, 0.786f, 0.522f, 0.524f, 0.055f, 0.0f, 0.785f, 0.525f, 0.525f, 0.066f, 0.0f, 0.785f, 0.527f, 0.525f,
+ 0.076f, 0.0f, 0.784f, 0.53f, 0.53f, 0.086f, 0.0f, 0.783f, 0.532f, 0.533f, 0.097f, 0.0f, 0.782f, 0.535f, 0.534f, 0.108f, 0.0f, 0.782f, 0.538f, 0.541f,
+ 0.119f, 0.0f, 0.781f, 0.54f, 0.542f, 0.13f, 0.0f, 0.781f, 0.543f, 0.543f, 0.141f, 0.0f, 0.78f, 0.545f, 0.545f, 0.154f, 0.0f, 0.779f, 0.547f, 0.547f,
+ 0.165f, 0.0f, 0.777f, 0.549f, 0.548f, 0.177f, 0.0f, 0.775f, 0.55f, 0.552f, 0.188f, 0.0f, 0.772f, 0.552f, 0.552f, 0.199f, 0.0f, 0.77f, 0.553f, 0.553f,
+ 0.209f, 0.0f, 0.767f, 0.554f, 0.554f, 0.218f, 0.0f, 0.765f, 0.555f, 0.556f, 0.226f, 0.0f, 0.763f, 0.556f, 0.557f, 0.235f, 0.0f, 0.761f, 0.557f, 0.557f,
+ 0.244f, 0.0f, 0.758f, 0.558f, 0.558f, 0.253f, 0.0f, 0.755f, 0.559f, 0.559f, 0.263f, 0.0f, 0.752f, 0.56f, 0.559f, 0.272f, 0.0f, 0.749f, 0.561f, 0.56f,
+ 0.285f, 0.0f, 0.745f, 0.562f, 0.56f, 0.299f, 0.0f, 0.741f, 0.563f, 0.563f, 0.316f, 0.0f, 0.736f, 0.564f, 0.564f, 0.331f, 0.0f, 0.728f, 0.565f, 0.567f,
+ 0.349f, 0.0f, 0.718f, 0.565f, 0.568f, 0.365f, 0.0f, 0.708f, 0.566f, 0.568f, 0.38f, 0.0f, 0.699f, 0.566f, 0.568f, 0.39f, 0.0f, 0.693f, 0.566f, 0.568f,
+ 0.397f, 0.0f, 0.687f, 0.566f, 0.569f, 0.4f, 0.0f, 0.683f, 0.566f, 0.569f, 0.401f, 0.0f, 0.681f, 0.565f, 0.57f, 0.4f, 0.0f, 0.679f, 0.565f, 0.57f,
+ 0.397f, 0.0f, 0.678f, 0.564f, 0.57f, 0.393f, 0.0f, 0.678f, 0.564f, 0.565f, 0.387f, 0.0f, 0.678f, 0.563f, 0.559f, 0.379f, 0.0f, 0.679f, 0.562f, 0.558f,
+ 0.37f, 0.0f, 0.681f, 0.561f, 0.557f, 0.357f, 0.0f, 0.684f, 0.561f, 0.557f, 0.342f, 0.0f, 0.689f, 0.56f, 0.557f, 0.324f, 0.0f, 0.694f, 0.56f, 0.557f,
+ 0.307f, 0.0f, 0.697f, 0.559f, 0.558f, 0.291f, 0.0f, 0.699f, 0.559f, 0.558f, 0.274f, 0.0f, 0.701f, 0.559f, 0.557f, 0.26f, 0.0f, 0.703f, 0.558f, 0.558f,
+ 0.246f, 0.0f, 0.705f, 0.558f, 0.558f, 0.235f, 0.0f, 0.707f, 0.558f, 0.558f, 0.224f, 0.0f, 0.709f, 0.558f, 0.558f, 0.214f, 0.0f, 0.711f, 0.558f, 0.558f,
+ 0.203f, 0.0f, 0.713f, 0.558f, 0.559f, 0.192f, 0.0f, 0.714f, 0.558f, 0.558f, 0.181f, 0.0f, 0.714f, 0.557f, 0.557f, 0.17f, 0.0f, 0.714f, 0.557f, 0.557f,
+ 0.16f, 0.0f, 0.715f, 0.557f, 0.556f, 0.149f, 0.0f, 0.715f, 0.557f, 0.556f, 0.139f, 0.0f, 0.716f, 0.557f, 0.556f, 0.129f, 0.0f, 0.716f, 0.558f, 0.556f,
+ 0.119f, 0.0f, 0.717f, 0.558f, 0.556f, 0.109f, 0.0f, 0.717f, 0.558f, 0.557f, 0.099f, 0.0f, 0.718f, 0.558f, 0.557f, 0.089f, 0.0f, 0.718f, 0.559f, 0.557f,
+ 0.079f, 0.0f, 0.718f, 0.559f, 0.558f, 0.068f, 0.0f, 0.719f, 0.559f, 0.559f, 0.057f, 0.0f, 0.719f, 0.56f, 0.56f, 0.046f, 0.0f, 0.718f, 0.56f, 0.561f,
+ 0.035f, 0.0f, 0.718f, 0.561f, 0.561f, 0.024f, 0.0f, 0.718f, 0.561f, 0.562f, 0.013f, 0.0f, 0.717f, 0.562f, 0.562f, 0.002f, 0.0f, 0.717f, 0.562f, 0.563f,
+ -0.01f, 0.0f, 0.717f, 0.563f, 0.564f, -0.021f, 0.0f, 0.717f, 0.563f, 0.564f, -0.032f, 0.0f, 0.716f, 0.563f, 0.564f, -0.044f, 0.0f, 0.715f, 0.564f, 0.564f,
+ -0.055f, 0.0f, 0.714f, 0.564f, 0.565f, -0.066f, 0.0f, 0.713f, 0.564f, 0.565f, -0.078f, 0.0f, 0.712f, 0.564f, 0.564f, -0.089f, 0.0f, 0.711f, 0.564f, 0.564f,
+ -0.101f, 0.0f, 0.709f, 0.565f, 0.564f, -0.112f, 0.0f, 0.708f, 0.565f, 0.564f, -0.124f, 0.0f, 0.707f, 0.565f, 0.564f, -0.135f, 0.0f, 0.705f, 0.565f, 0.564f,
+ -0.146f, 0.0f, 0.704f, 0.566f, 0.564f, -0.158f, 0.0f, 0.702f, 0.566f, 0.564f, -0.169f, 0.0f, 0.7f, 0.566f, 0.566f, -0.18f, 0.0f, 0.698f, 0.567f, 0.568f,
+ -0.191f, 0.0f, 0.696f, 0.567f, 0.568f, -0.203f, 0.0f, 0.693f, 0.567f, 0.568f, -0.215f, 0.0f, 0.69f, 0.567f, 0.568f, -0.227f, 0.0f, 0.687f, 0.567f, 0.568f,
+ -0.238f, 0.0f, 0.684f, 0.567f, 0.568f, -0.25f, 0.0f, 0.681f, 0.567f, 0.569f, -0.262f, 0.0f, 0.678f, 0.567f, 0.569f, -0.273f, 0.0f, 0.675f, 0.567f, 0.567f,
+ -0.284f, 0.0f, 0.673f, 0.567f, 0.566f, -0.295f, 0.0f, 0.671f, 0.567f, 0.567f, -0.305f, 0.0f, 0.669f, 0.566f, 0.567f, -0.316f, 0.0f, 0.666f, 0.566f, 0.567f,
+ -0.326f, 0.0f, 0.663f, 0.565f, 0.566f, -0.337f, 0.0f, 0.66f, 0.565f, 0.566f, -0.348f, 0.0f, 0.655f, 0.564f, 0.564f, -0.359f, 0.0f, 0.652f, 0.563f, 0.564f,
+ -0.369f, 0.0f, 0.648f, 0.562f, 0.563f, -0.379f, 0.0f, 0.644f, 0.561f, 0.56f, -0.389f, 0.0f, 0.64f, 0.561f, 0.559f, -0.399f, 0.0f, 0.636f, 0.56f, 0.559f,
+ -0.409f, 0.0f, 0.633f, 0.559f, 0.559f, -0.419f, 0.0f, 0.629f, 0.559f, 0.559f, -0.428f, 0.0f, 0.625f, 0.559f, 0.558f, -0.438f, 0.0f, 0.62f, 0.559f, 0.559f,
+ -0.447f, 0.0f, 0.615f, 0.559f, 0.559f, -0.457f, 0.0f, 0.61f, 0.559f, 0.559f, -0.466f, 0.0f, 0.605f, 0.559f, 0.559f, -0.474f, 0.0f, 0.6f, 0.559f, 0.559f,
+ -0.483f, 0.0f, 0.595f, 0.559f, 0.559f, -0.492f, 0.0f, 0.591f, 0.559f, 0.559f, -0.5f, 0.0f, 0.586f, 0.559f, 0.559f, -0.508f, 0.0f, 0.58f, 0.559f, 0.559f,
+ -0.515f, 0.0f, 0.574f, 0.559f, 0.559f, -0.523f, 0.0f, 0.568f, 0.559f, 0.559f, -0.531f, 0.0f, 0.562f, 0.559f, 0.558f, -0.54f, 0.0f, 0.556f, 0.559f, 0.558f,
+ -0.548f, 0.0f, 0.549f, 0.559f, 0.559f, -0.556f, 0.0f, 0.543f, 0.559f, 0.559f, -0.562f, 0.0f, 0.537f, 0.559f, 0.559f, -0.568f, 0.0f, 0.531f, 0.559f, 0.559f,
+ -0.574f, 0.0f, 0.524f, 0.559f, 0.559f, -0.58f, 0.0f, 0.518f, 0.558f, 0.559f, -0.586f, 0.0f, 0.512f, 0.557f, 0.558f, -0.591f, 0.0f, 0.506f, 0.555f, 0.557f,
+ -0.597f, 0.0f, 0.5f, 0.551f, 0.556f, -0.603f, 0.0f, 0.493f, 0.546f, 0.547f, -0.609f, 0.0f, 0.487f, 0.541f, 0.538f, -0.614f, 0.0f, 0.48f, 0.536f, 0.535f,
+ -0.621f, 0.0f, 0.473f, 0.534f, 0.534f, -0.628f, 0.0f, 0.467f, 0.534f, 0.534f, -0.637f, 0.0f, 0.459f, 0.534f, 0.534f, -0.642f, 0.0f, 0.452f, 0.532f, 0.532f,
+ -0.65f, 0.0f, 0.445f, 0.528f, 0.528f, -0.654f, 0.0f, 0.438f, 0.525f, 0.525f, -0.659f, 0.0f, 0.431f, 0.522f, 0.522f,
+};
+
+static const float data11[1 * GP_PRIM_DATABUF_SIZE] = {
+ -0.525f, 0.0f, 0.174f, 0.124f, 0.124f,
+};
+
+static const float data12[123 * GP_PRIM_DATABUF_SIZE] = {
+ -0.53f, 0.0f, 0.193f, 0.147f, 0.147f, -0.532f, 0.0f, 0.186f, 0.316f, 0.316f, -0.534f, 0.0f, 0.18f, 0.353f, 0.353f, -0.535f, 0.0f, 0.173f, 0.382f, 0.382f,
+ -0.537f, 0.0f, 0.165f, 0.384f, 0.384f, -0.538f, 0.0f, 0.155f, 0.387f, 0.387f, -0.539f, 0.0f, 0.145f, 0.393f, 0.393f, -0.54f, -0.0f, 0.134f, 0.399f, 0.399f,
+ -0.541f, -0.0f, 0.123f, 0.4f, 0.4f, -0.542f, -0.0f, 0.11f, 0.401f, 0.401f, -0.542f, 0.0f, 0.094f, 0.402f, 0.402f, -0.54f, 0.0f, 0.078f, 0.403f, 0.403f,
+ -0.538f, 0.0f, 0.061f, 0.404f, 0.404f, -0.535f, 0.0f, 0.045f, 0.404f, 0.404f, -0.531f, 0.0f, 0.031f, 0.404f, 0.404f, -0.526f, 0.0f, 0.018f, 0.404f, 0.404f,
+ -0.52f, -0.0f, 0.005f, 0.405f, 0.405f, -0.513f, -0.0f, -0.01f, 0.405f, 0.405f, -0.505f, -0.0f, -0.024f, 0.405f, 0.405f, -0.495f, -0.0f, -0.037f, 0.405f, 0.405f,
+ -0.485f, 0.0f, -0.051f, 0.405f, 0.405f, -0.474f, 0.0f, -0.064f, 0.406f, 0.406f, -0.462f, 0.0f, -0.076f, 0.405f, 0.405f, -0.451f, 0.0f, -0.086f, 0.406f, 0.406f,
+ -0.442f, 0.0f, -0.094f, 0.406f, 0.406f, -0.432f, 0.0f, -0.102f, 0.406f, 0.406f, -0.422f, 0.0f, -0.108f, 0.405f, 0.405f, -0.411f, 0.0f, -0.114f, 0.406f, 0.406f,
+ -0.4f, 0.0f, -0.119f, 0.405f, 0.405f, -0.389f, 0.0f, -0.122f, 0.406f, 0.406f, -0.378f, 0.0f, -0.125f, 0.407f, 0.407f, -0.365f, 0.0f, -0.127f, 0.412f, 0.412f,
+ -0.354f, 0.0f, -0.129f, 0.418f, 0.418f, -0.342f, 0.0f, -0.131f, 0.44f, 0.44f, -0.33f, 0.0f, -0.131f, 0.448f, 0.448f, -0.317f, 0.0f, -0.131f, 0.469f, 0.469f,
+ -0.305f, 0.0f, -0.13f, 0.477f, 0.477f, -0.293f, 0.0f, -0.128f, 0.482f, 0.482f, -0.278f, 0.0f, -0.125f, 0.494f, 0.494f, -0.266f, 0.0f, -0.121f, 0.5f, 0.5f,
+ -0.253f, 0.0f, -0.116f, 0.507f, 0.507f, -0.242f, 0.0f, -0.111f, 0.509f, 0.509f, -0.231f, 0.0f, -0.105f, 0.511f, 0.511f, -0.222f, 0.0f, -0.099f, 0.511f, 0.511f,
+ -0.213f, 0.0f, -0.092f, 0.512f, 0.512f, -0.206f, 0.0f, -0.084f, 0.513f, 0.513f, -0.199f, 0.0f, -0.076f, 0.514f, 0.514f, -0.192f, 0.0f, -0.067f, 0.515f, 0.515f,
+ -0.186f, -0.0f, -0.058f, 0.516f, 0.516f, -0.18f, -0.0f, -0.049f, 0.516f, 0.516f, -0.175f, -0.0f, -0.04f, 0.515f, 0.515f, -0.17f, -0.0f, -0.03f, 0.515f, 0.515f,
+ -0.166f, -0.0f, -0.02f, 0.516f, 0.516f, -0.163f, -0.0f, -0.01f, 0.504f, 0.504f, -0.159f, -0.0f, 0.002f, 0.502f, 0.502f, -0.155f, -0.0f, 0.014f, 0.501f, 0.501f,
+ -0.152f, -0.0f, 0.027f, 0.502f, 0.502f, -0.149f, -0.0f, 0.043f, 0.5f, 0.5f, -0.148f, -0.0f, 0.058f, 0.49f, 0.49f, -0.147f, -0.0f, 0.075f, 0.47f, 0.47f,
+ -0.146f, -0.0f, 0.09f, 0.463f, 0.463f, -0.146f, -0.0f, 0.105f, 0.454f, 0.454f, -0.146f, -0.0f, 0.12f, 0.427f, 0.427f, -0.148f, 0.0f, 0.133f, 0.413f, 0.413f,
+ -0.15f, 0.0f, 0.144f, 0.4f, 0.4f, -0.153f, 0.0f, 0.152f, 0.383f, 0.383f, -0.156f, 0.0f, 0.157f, 0.369f, 0.369f, -0.158f, 0.0f, 0.16f, 0.36f, 0.36f,
+ -0.16f, 0.0f, 0.158f, 0.349f, 0.349f, -0.162f, 0.0f, 0.154f, 0.364f, 0.364f, -0.164f, 0.0f, 0.147f, 0.37f, 0.37f, -0.166f, 0.0f, 0.139f, 0.378f, 0.378f,
+ -0.168f, 0.0f, 0.13f, 0.386f, 0.386f, -0.172f, 0.0f, 0.119f, 0.394f, 0.394f, -0.176f, -0.0f, 0.108f, 0.405f, 0.405f, -0.18f, -0.0f, 0.096f, 0.412f, 0.412f,
+ -0.185f, -0.0f, 0.084f, 0.417f, 0.417f, -0.191f, -0.0f, 0.073f, 0.425f, 0.425f, -0.196f, -0.0f, 0.063f, 0.431f, 0.431f, -0.202f, -0.0f, 0.053f, 0.441f, 0.441f,
+ -0.208f, -0.0f, 0.043f, 0.444f, 0.444f, -0.214f, -0.0f, 0.034f, 0.451f, 0.451f, -0.22f, 0.0f, 0.026f, 0.46f, 0.46f, -0.226f, 0.0f, 0.018f, 0.463f, 0.463f,
+ -0.232f, 0.0f, 0.01f, 0.474f, 0.474f, -0.239f, 0.0f, 0.004f, 0.477f, 0.477f, -0.247f, 0.0f, -0.003f, 0.48f, 0.48f, -0.255f, 0.0f, -0.008f, 0.483f, 0.483f,
+ -0.264f, 0.0f, -0.013f, 0.497f, 0.497f, -0.274f, 0.0f, -0.018f, 0.501f, 0.501f, -0.285f, 0.0f, -0.022f, 0.505f, 0.505f, -0.297f, 0.0f, -0.024f, 0.509f, 0.509f,
+ -0.311f, 0.0f, -0.025f, 0.51f, 0.51f, -0.325f, 0.0f, -0.024f, 0.512f, 0.512f, -0.339f, 0.0f, -0.023f, 0.512f, 0.512f, -0.354f, 0.0f, -0.022f, 0.513f, 0.513f,
+ -0.368f, 0.0f, -0.02f, 0.513f, 0.513f, -0.382f, 0.0f, -0.017f, 0.514f, 0.514f, -0.397f, 0.0f, -0.013f, 0.514f, 0.514f, -0.41f, 0.0f, -0.007f, 0.514f, 0.514f,
+ -0.422f, 0.0f, 0.001f, 0.513f, 0.513f, -0.434f, 0.0f, 0.009f, 0.514f, 0.514f, -0.446f, 0.0f, 0.018f, 0.514f, 0.514f, -0.458f, 0.0f, 0.028f, 0.514f, 0.514f,
+ -0.47f, -0.0f, 0.039f, 0.514f, 0.514f, -0.48f, 0.0f, 0.048f, 0.514f, 0.514f, -0.487f, 0.0f, 0.057f, 0.514f, 0.514f, -0.493f, 0.0f, 0.068f, 0.514f, 0.514f,
+ -0.498f, 0.0f, 0.08f, 0.514f, 0.514f, -0.502f, 0.0f, 0.092f, 0.514f, 0.514f, -0.506f, 0.0f, 0.104f, 0.514f, 0.514f, -0.509f, -0.0f, 0.116f, 0.515f, 0.515f,
+ -0.511f, -0.0f, 0.125f, 0.515f, 0.515f, -0.513f, -0.0f, 0.133f, 0.515f, 0.515f, -0.515f, -0.0f, 0.141f, 0.515f, 0.515f, -0.517f, 0.0f, 0.148f, 0.515f, 0.515f,
+ -0.519f, 0.0f, 0.155f, 0.514f, 0.514f, -0.52f, 0.0f, 0.161f, 0.514f, 0.514f, -0.522f, 0.0f, 0.168f, 0.514f, 0.514f, -0.523f, 0.0f, 0.174f, 0.514f, 0.514f,
+ -0.525f, 0.0f, 0.18f, 0.514f, 0.514f, -0.526f, 0.0f, 0.185f, 0.514f, 0.514f, -0.527f, 0.0f, 0.191f, 0.513f, 0.513f,
+};
+
+static const float data13[125 * GP_PRIM_DATABUF_SIZE] = {
+ 0.184f, 0.0f, 0.22f, 0.026f, 0.026f, 0.182f, 0.0f, 0.21f, 0.275f, 0.275f, 0.18f, 0.0f, 0.203f, 0.301f, 0.301f, 0.178f, 0.0f, 0.195f, 0.322f, 0.322f,
+ 0.176f, 0.0f, 0.186f, 0.343f, 0.343f, 0.173f, 0.0f, 0.176f, 0.36f, 0.36f, 0.17f, -0.0f, 0.166f, 0.367f, 0.367f, 0.168f, -0.0f, 0.156f, 0.38f, 0.38f,
+ 0.165f, -0.0f, 0.145f, 0.385f, 0.385f, 0.163f, -0.0f, 0.132f, 0.391f, 0.391f, 0.161f, -0.0f, 0.119f, 0.401f, 0.401f, 0.16f, -0.0f, 0.103f, 0.405f, 0.405f,
+ 0.161f, -0.0f, 0.086f, 0.405f, 0.405f, 0.163f, -0.0f, 0.068f, 0.407f, 0.407f, 0.165f, 0.0f, 0.051f, 0.409f, 0.409f, 0.168f, 0.0f, 0.034f, 0.409f, 0.409f,
+ 0.172f, 0.0f, 0.018f, 0.409f, 0.409f, 0.177f, 0.0f, 0.004f, 0.409f, 0.409f, 0.183f, 0.0f, -0.008f, 0.411f, 0.411f, 0.19f, 0.0f, -0.022f, 0.411f, 0.411f,
+ 0.196f, 0.0f, -0.034f, 0.411f, 0.411f, 0.203f, 0.0f, -0.045f, 0.411f, 0.411f, 0.211f, 0.0f, -0.055f, 0.411f, 0.411f, 0.219f, 0.0f, -0.064f, 0.411f, 0.411f,
+ 0.227f, 0.0f, -0.072f, 0.411f, 0.411f, 0.235f, 0.0f, -0.08f, 0.412f, 0.412f, 0.244f, 0.0f, -0.087f, 0.412f, 0.412f, 0.253f, 0.0f, -0.094f, 0.413f, 0.413f,
+ 0.262f, 0.0f, -0.1f, 0.413f, 0.413f, 0.273f, 0.0f, -0.105f, 0.413f, 0.413f, 0.284f, 0.0f, -0.11f, 0.413f, 0.413f, 0.295f, 0.0f, -0.114f, 0.419f, 0.419f,
+ 0.307f, 0.0f, -0.117f, 0.425f, 0.425f, 0.321f, -0.0f, -0.118f, 0.433f, 0.433f, 0.334f, -0.0f, -0.12f, 0.446f, 0.446f, 0.347f, -0.0f, -0.12f, 0.474f, 0.474f,
+ 0.36f, -0.0f, -0.12f, 0.481f, 0.481f, 0.374f, -0.0f, -0.119f, 0.491f, 0.491f, 0.387f, -0.0f, -0.118f, 0.494f, 0.494f, 0.401f, 0.0f, -0.116f, 0.5f, 0.5f,
+ 0.414f, 0.0f, -0.112f, 0.505f, 0.505f, 0.426f, -0.0f, -0.107f, 0.51f, 0.51f, 0.438f, -0.0f, -0.101f, 0.513f, 0.513f, 0.449f, -0.0f, -0.094f, 0.515f, 0.515f,
+ 0.46f, -0.0f, -0.086f, 0.517f, 0.517f, 0.47f, -0.0f, -0.078f, 0.519f, 0.519f, 0.478f, -0.0f, -0.07f, 0.52f, 0.52f, 0.486f, -0.0f, -0.061f, 0.522f, 0.522f,
+ 0.493f, -0.0f, -0.052f, 0.523f, 0.523f, 0.499f, -0.0f, -0.044f, 0.522f, 0.522f, 0.505f, -0.0f, -0.035f, 0.522f, 0.522f, 0.51f, -0.0f, -0.027f, 0.523f, 0.523f,
+ 0.514f, -0.0f, -0.018f, 0.523f, 0.523f, 0.517f, -0.0f, -0.009f, 0.523f, 0.523f, 0.52f, -0.0f, -0.001f, 0.524f, 0.524f, 0.522f, -0.0f, 0.008f, 0.523f, 0.523f,
+ 0.525f, -0.0f, 0.018f, 0.521f, 0.522f, 0.527f, -0.0f, 0.027f, 0.515f, 0.514f, 0.529f, -0.0f, 0.036f, 0.512f, 0.512f, 0.531f, -0.0f, 0.045f, 0.509f, 0.51f,
+ 0.533f, -0.0f, 0.053f, 0.506f, 0.505f, 0.535f, -0.0f, 0.062f, 0.503f, 0.503f, 0.536f, -0.0f, 0.071f, 0.5f, 0.5f, 0.538f, -0.0f, 0.08f, 0.496f, 0.497f,
+ 0.538f, -0.0f, 0.09f, 0.491f, 0.492f, 0.539f, -0.0f, 0.1f, 0.485f, 0.486f, 0.539f, 0.0f, 0.11f, 0.475f, 0.476f, 0.539f, 0.0f, 0.12f, 0.46f, 0.459f,
+ 0.539f, 0.0f, 0.13f, 0.444f, 0.448f, 0.538f, 0.0f, 0.139f, 0.406f, 0.405f, 0.537f, 0.0f, 0.144f, 0.399f, 0.399f, 0.536f, 0.0f, 0.146f, 0.395f, 0.395f,
+ 0.535f, 0.0f, 0.144f, 0.412f, 0.412f, 0.533f, 0.0f, 0.139f, 0.413f, 0.413f, 0.53f, 0.0f, 0.131f, 0.414f, 0.413f, 0.528f, 0.0f, 0.122f, 0.419f, 0.418f,
+ 0.525f, 0.0f, 0.112f, 0.425f, 0.424f, 0.521f, 0.0f, 0.102f, 0.444f, 0.444f, 0.518f, 0.0f, 0.094f, 0.451f, 0.452f, 0.514f, 0.0f, 0.085f, 0.457f, 0.457f,
+ 0.509f, 0.0f, 0.078f, 0.461f, 0.46f, 0.504f, 0.0f, 0.069f, 0.469f, 0.468f, 0.499f, 0.0f, 0.06f, 0.481f, 0.481f, 0.493f, 0.0f, 0.052f, 0.489f, 0.489f,
+ 0.487f, 0.0f, 0.044f, 0.492f, 0.492f, 0.481f, 0.0f, 0.037f, 0.501f, 0.5f, 0.474f, 0.0f, 0.029f, 0.513f, 0.513f, 0.467f, 0.0f, 0.022f, 0.521f, 0.521f,
+ 0.458f, 0.0f, 0.015f, 0.524f, 0.524f, 0.449f, 0.0f, 0.008f, 0.525f, 0.525f, 0.439f, 0.0f, 0.001f, 0.528f, 0.528f, 0.427f, 0.0f, -0.005f, 0.532f, 0.532f,
+ 0.416f, 0.0f, -0.011f, 0.533f, 0.533f, 0.401f, 0.0f, -0.015f, 0.537f, 0.537f, 0.386f, 0.0f, -0.018f, 0.539f, 0.539f, 0.371f, 0.0f, -0.02f, 0.538f, 0.538f,
+ 0.356f, 0.0f, -0.021f, 0.543f, 0.543f, 0.341f, 0.0f, -0.023f, 0.543f, 0.543f, 0.326f, 0.0f, -0.023f, 0.543f, 0.543f, 0.312f, 0.0f, -0.022f, 0.543f, 0.543f,
+ 0.298f, 0.0f, -0.018f, 0.543f, 0.543f, 0.286f, 0.0f, -0.014f, 0.543f, 0.543f, 0.273f, 0.0f, -0.006f, 0.543f, 0.543f, 0.26f, 0.0f, 0.004f, 0.543f, 0.543f,
+ 0.247f, 0.0f, 0.013f, 0.543f, 0.543f, 0.235f, 0.0f, 0.022f, 0.543f, 0.543f, 0.225f, 0.0f, 0.033f, 0.543f, 0.543f, 0.215f, 0.0f, 0.045f, 0.542f, 0.542f,
+ 0.206f, 0.0f, 0.061f, 0.54f, 0.54f, 0.199f, 0.0f, 0.078f, 0.542f, 0.542f, 0.193f, 0.0f, 0.094f, 0.542f, 0.542f, 0.189f, -0.0f, 0.109f, 0.541f, 0.541f,
+ 0.186f, -0.0f, 0.119f, 0.542f, 0.542f, 0.185f, -0.0f, 0.127f, 0.542f, 0.542f, 0.184f, -0.0f, 0.135f, 0.542f, 0.542f, 0.184f, -0.0f, 0.142f, 0.542f, 0.542f,
+ 0.183f, -0.0f, 0.149f, 0.541f, 0.541f, 0.183f, -0.0f, 0.156f, 0.538f, 0.538f, 0.183f, -0.0f, 0.163f, 0.539f, 0.539f, 0.183f, -0.0f, 0.17f, 0.54f, 0.54f,
+ 0.183f, 0.0f, 0.177f, 0.54f, 0.54f, 0.183f, 0.0f, 0.184f, 0.54f, 0.54f, 0.183f, 0.0f, 0.191f, 0.54f, 0.54f, 0.184f, 0.0f, 0.196f, 0.539f, 0.539f,
+ 0.184f, 0.0f, 0.204f, 0.518f, 0.518f,
+};
+
+static const float data14[45 * GP_PRIM_DATABUF_SIZE] = {
+ -0.096f, -0.0f, -0.305f, 0.01f, 0.01f, -0.09f, -0.0f, -0.313f, 0.121f, 0.362f, -0.086f, -0.0f, -0.318f, 0.179f, 0.368f, -0.081f, -0.0f, -0.325f, 0.234f, 0.37f,
+ -0.075f, -0.0f, -0.331f, 0.272f, 0.37f, -0.068f, -0.0f, -0.338f, 0.302f, 0.371f, -0.061f, -0.0f, -0.345f, 0.324f, 0.374f, -0.053f, -0.0f, -0.352f, 0.34f, 0.377f,
+ -0.044f, -0.0f, -0.358f, 0.352f, 0.378f, -0.035f, -0.0f, -0.362f, 0.362f, 0.377f, -0.026f, -0.0f, -0.366f, 0.37f, 0.378f, -0.018f, -0.0f, -0.368f, 0.377f, 0.378f,
+ -0.009f, -0.0f, -0.369f, 0.383f, 0.376f, -0.001f, -0.0f, -0.369f, 0.389f, 0.369f, 0.007f, -0.0f, -0.368f, 0.395f, 0.364f, 0.015f, -0.0f, -0.367f, 0.4f, 0.388f,
+ 0.023f, -0.0f, -0.365f, 0.405f, 0.41f, 0.03f, -0.0f, -0.363f, 0.41f, 0.429f, 0.038f, -0.0f, -0.36f, 0.414f, 0.438f, 0.044f, -0.0f, -0.357f, 0.417f, 0.441f,
+ 0.05f, -0.0f, -0.355f, 0.419f, 0.444f, 0.055f, -0.0f, -0.352f, 0.42f, 0.441f, 0.06f, -0.0f, -0.349f, 0.421f, 0.445f, 0.063f, -0.0f, -0.347f, 0.421f, 0.446f,
+ 0.065f, -0.0f, -0.344f, 0.42f, 0.443f, 0.065f, -0.0f, -0.342f, 0.42f, 0.437f, 0.065f, -0.0f, -0.341f, 0.419f, 0.413f, 0.063f, -0.0f, -0.339f, 0.418f, 0.404f,
+ 0.061f, -0.0f, -0.338f, 0.418f, 0.403f, 0.057f, -0.0f, -0.337f, 0.418f, 0.402f, 0.052f, -0.0f, -0.337f, 0.418f, 0.407f, 0.046f, -0.0f, -0.337f, 0.419f, 0.411f,
+ 0.04f, 0.0f, -0.336f, 0.42f, 0.416f, 0.032f, 0.0f, -0.337f, 0.422f, 0.421f, 0.023f, 0.0f, -0.339f, 0.424f, 0.425f, 0.014f, 0.0f, -0.34f, 0.426f, 0.427f,
+ 0.003f, 0.0f, -0.341f, 0.428f, 0.427f, -0.007f, 0.0f, -0.341f, 0.43f, 0.433f, -0.018f, 0.0f, -0.339f, 0.432f, 0.437f, -0.027f, 0.0f, -0.335f, 0.434f, 0.438f,
+ -0.037f, 0.0f, -0.33f, 0.435f, 0.437f, -0.046f, -0.0f, -0.326f, 0.436f, 0.438f, -0.055f, -0.0f, -0.321f, 0.436f, 0.44f, -0.062f, -0.0f, -0.316f, 0.437f, 0.439f,
+ -0.073f, -0.0f, -0.31f, 0.437f, 0.437f,
+};
+
+static const float data16[84 * GP_PRIM_DATABUF_SIZE] = {
+ 0.737f, 0.0f, 0.177f, 0.148f, 0.148f, 0.735f, 0.0f, 0.164f, 0.214f, 0.39f, 0.734f, 0.0f, 0.155f, 0.254f, 0.402f, 0.732f, 0.0f, 0.143f, 0.295f, 0.413f,
+ 0.73f, 0.0f, 0.132f, 0.328f, 0.415f, 0.728f, 0.0f, 0.121f, 0.355f, 0.415f, 0.726f, 0.0f, 0.109f, 0.375f, 0.416f, 0.724f, 0.0f, 0.097f, 0.39f, 0.417f,
+ 0.721f, 0.0f, 0.086f, 0.401f, 0.418f, 0.719f, 0.0f, 0.074f, 0.408f, 0.419f, 0.716f, 0.0f, 0.062f, 0.413f, 0.42f, 0.713f, 0.0f, 0.05f, 0.416f, 0.42f,
+ 0.71f, 0.0f, 0.039f, 0.418f, 0.421f, 0.707f, 0.0f, 0.028f, 0.42f, 0.421f, 0.703f, 0.0f, 0.017f, 0.421f, 0.422f, 0.7f, 0.0f, 0.006f, 0.421f, 0.422f,
+ 0.696f, 0.0f, -0.005f, 0.422f, 0.422f, 0.693f, 0.0f, -0.015f, 0.422f, 0.422f, 0.689f, 0.0f, -0.025f, 0.423f, 0.423f, 0.685f, 0.0f, -0.034f, 0.423f, 0.423f,
+ 0.681f, 0.0f, -0.044f, 0.423f, 0.423f, 0.677f, 0.0f, -0.053f, 0.423f, 0.423f, 0.672f, 0.0f, -0.062f, 0.423f, 0.423f, 0.668f, 0.0f, -0.071f, 0.422f, 0.424f,
+ 0.662f, 0.0f, -0.08f, 0.422f, 0.424f, 0.657f, 0.0f, -0.088f, 0.422f, 0.422f, 0.651f, 0.0f, -0.095f, 0.421f, 0.419f, 0.645f, 0.0f, -0.103f, 0.42f, 0.419f,
+ 0.638f, 0.0f, -0.109f, 0.42f, 0.419f, 0.631f, 0.0f, -0.115f, 0.419f, 0.419f, 0.624f, 0.0f, -0.12f, 0.419f, 0.419f, 0.617f, 0.0f, -0.125f, 0.419f, 0.419f,
+ 0.61f, 0.0f, -0.129f, 0.418f, 0.418f, 0.602f, 0.0f, -0.133f, 0.418f, 0.416f, 0.594f, 0.0f, -0.137f, 0.417f, 0.416f, 0.587f, 0.0f, -0.14f, 0.417f, 0.415f,
+ 0.579f, 0.0f, -0.142f, 0.417f, 0.416f, 0.571f, 0.0f, -0.144f, 0.417f, 0.415f, 0.564f, 0.0f, -0.145f, 0.417f, 0.416f, 0.556f, 0.0f, -0.146f, 0.417f, 0.415f,
+ 0.549f, 0.0f, -0.146f, 0.417f, 0.415f, 0.541f, 0.0f, -0.146f, 0.417f, 0.415f, 0.535f, 0.0f, -0.145f, 0.417f, 0.416f, 0.53f, 0.0f, -0.143f, 0.418f, 0.418f,
+ 0.526f, 0.0f, -0.14f, 0.418f, 0.418f, 0.524f, 0.0f, -0.136f, 0.42f, 0.418f, 0.524f, 0.0f, -0.132f, 0.422f, 0.416f, 0.527f, 0.0f, -0.126f, 0.424f, 0.424f,
+ 0.531f, 0.0f, -0.121f, 0.427f, 0.428f, 0.536f, 0.0f, -0.115f, 0.43f, 0.433f, 0.542f, 0.0f, -0.109f, 0.433f, 0.436f, 0.548f, 0.0f, -0.102f, 0.435f, 0.436f,
+ 0.555f, 0.0f, -0.095f, 0.436f, 0.437f, 0.562f, 0.0f, -0.088f, 0.437f, 0.438f, 0.568f, 0.0f, -0.081f, 0.437f, 0.438f, 0.575f, 0.0f, -0.073f, 0.438f, 0.438f,
+ 0.581f, 0.0f, -0.065f, 0.438f, 0.438f, 0.587f, 0.0f, -0.058f, 0.438f, 0.438f, 0.593f, 0.0f, -0.05f, 0.438f, 0.438f, 0.599f, 0.0f, -0.041f, 0.438f, 0.438f,
+ 0.605f, 0.0f, -0.033f, 0.438f, 0.438f, 0.61f, 0.0f, -0.024f, 0.438f, 0.438f, 0.615f, 0.0f, -0.015f, 0.438f, 0.438f, 0.621f, 0.0f, -0.006f, 0.438f, 0.438f,
+ 0.626f, 0.0f, 0.004f, 0.438f, 0.438f, 0.631f, 0.0f, 0.013f, 0.437f, 0.438f, 0.636f, 0.0f, 0.023f, 0.436f, 0.438f, 0.641f, 0.0f, 0.032f, 0.434f, 0.438f,
+ 0.647f, 0.0f, 0.042f, 0.432f, 0.437f, 0.652f, 0.0f, 0.051f, 0.431f, 0.429f, 0.657f, 0.0f, 0.06f, 0.429f, 0.426f, 0.662f, 0.0f, 0.069f, 0.427f, 0.425f,
+ 0.668f, 0.0f, 0.078f, 0.425f, 0.425f, 0.673f, 0.0f, 0.087f, 0.423f, 0.424f, 0.678f, 0.0f, 0.095f, 0.42f, 0.422f, 0.683f, 0.0f, 0.104f, 0.416f, 0.42f,
+ 0.688f, 0.0f, 0.112f, 0.411f, 0.421f, 0.693f, 0.0f, 0.12f, 0.403f, 0.417f, 0.698f, 0.0f, 0.128f, 0.394f, 0.411f, 0.702f, 0.0f, 0.135f, 0.382f, 0.404f,
+ 0.707f, 0.0f, 0.143f, 0.369f, 0.388f, 0.711f, 0.0f, 0.15f, 0.352f, 0.371f, 0.714f, 0.0f, 0.155f, 0.338f, 0.352f, 0.719f, 0.0f, 0.164f, 0.315f, 0.315f,
+};
+
+static const float data15[44 * GP_PRIM_DATABUF_SIZE] = {
+ -0.085f, 0.0f, -0.816f, 0.138f, 0.138f, -0.079f, 0.0f, -0.825f, 0.246f, 0.309f, -0.074f, 0.0f, -0.832f, 0.302f, 0.34f, -0.067f, 0.0f, -0.84f, 0.335f, 0.352f,
+ -0.059f, 0.0f, -0.848f, 0.357f, 0.374f, -0.05f, 0.0f, -0.855f, 0.371f, 0.378f, -0.041f, 0.0f, -0.861f, 0.382f, 0.383f, -0.031f, 0.0f, -0.866f, 0.391f, 0.396f,
+ -0.021f, 0.0f, -0.871f, 0.398f, 0.401f, -0.011f, 0.0f, -0.874f, 0.404f, 0.407f, -0.001f, 0.0f, -0.877f, 0.409f, 0.411f, 0.01f, 0.0f, -0.878f, 0.415f, 0.412f,
+ 0.02f, 0.0f, -0.878f, 0.422f, 0.417f, 0.031f, 0.0f, -0.878f, 0.43f, 0.421f, 0.042f, 0.0f, -0.876f, 0.438f, 0.437f, 0.052f, 0.0f, -0.873f, 0.445f, 0.451f,
+ 0.062f, 0.0f, -0.868f, 0.451f, 0.459f, 0.071f, 0.0f, -0.863f, 0.456f, 0.463f, 0.08f, 0.0f, -0.857f, 0.46f, 0.465f, 0.087f, 0.0f, -0.85f, 0.462f, 0.465f,
+ 0.094f, 0.0f, -0.842f, 0.461f, 0.465f, 0.098f, 0.0f, -0.835f, 0.458f, 0.467f, 0.101f, 0.0f, -0.827f, 0.451f, 0.457f, 0.103f, 0.0f, -0.82f, 0.436f, 0.451f,
+ 0.102f, 0.0f, -0.815f, 0.422f, 0.418f, 0.1f, 0.0f, -0.811f, 0.419f, 0.378f, 0.096f, 0.0f, -0.814f, 0.436f, 0.447f, 0.089f, 0.0f, -0.817f, 0.454f, 0.465f,
+ 0.082f, 0.0f, -0.821f, 0.465f, 0.47f, 0.072f, 0.0f, -0.825f, 0.473f, 0.477f, 0.061f, 0.0f, -0.828f, 0.477f, 0.479f, 0.049f, 0.0f, -0.832f, 0.48f, 0.485f,
+ 0.036f, 0.0f, -0.834f, 0.483f, 0.48f, 0.023f, 0.0f, -0.836f, 0.484f, 0.485f, 0.01f, 0.0f, -0.838f, 0.486f, 0.487f, -0.003f, 0.0f, -0.84f, 0.486f, 0.488f,
+ -0.016f, 0.0f, -0.84f, 0.486f, 0.489f, -0.027f, 0.0f, -0.84f, 0.485f, 0.485f, -0.039f, 0.0f, -0.839f, 0.484f, 0.484f, -0.049f, 0.0f, -0.837f, 0.483f, 0.485f,
+ -0.058f, 0.0f, -0.834f, 0.48f, 0.481f, -0.066f, 0.0f, -0.83f, 0.473f, 0.479f, -0.072f, 0.0f, -0.827f, 0.462f, 0.472f, -0.081f, 0.0f, -0.823f, 0.442f, 0.442f,
+};
+
+static const float data17[56 * GP_PRIM_DATABUF_SIZE] = {
+ -1.007f, -0.0f, 0.183f, 0.022f, 0.022f, -1.003f, -0.0f, 0.181f, 0.192f, 0.436f, -0.998f, -0.0f, 0.18f, 0.28f, 0.451f, -0.99f, -0.0f, 0.178f, 0.355f, 0.459f,
+ -0.98f, -0.0f, 0.175f, 0.402f, 0.464f, -0.967f, -0.0f, 0.169f, 0.432f, 0.467f, -0.952f, -0.0f, 0.152f, 0.449f, 0.468f, -0.943f, 0.0f, 0.138f, 0.459f, 0.469f,
+ -0.939f, 0.0f, 0.128f, 0.464f, 0.469f, -0.934f, 0.0f, 0.119f, 0.467f, 0.47f, -0.929f, 0.0f, 0.11f, 0.469f, 0.47f, -0.924f, 0.0f, 0.101f, 0.47f, 0.47f,
+ -0.919f, 0.0f, 0.092f, 0.47f, 0.471f, -0.913f, 0.0f, 0.082f, 0.471f, 0.471f, -0.908f, 0.0f, 0.072f, 0.471f, 0.471f, -0.903f, 0.0f, 0.063f, 0.472f, 0.472f,
+ -0.897f, 0.0f, 0.053f, 0.472f, 0.472f, -0.892f, 0.0f, 0.044f, 0.473f, 0.473f, -0.886f, 0.0f, 0.035f, 0.473f, 0.473f, -0.881f, 0.0f, 0.026f, 0.473f, 0.473f,
+ -0.876f, 0.0f, 0.018f, 0.473f, 0.473f, -0.87f, 0.0f, 0.012f, 0.472f, 0.473f, -0.865f, 0.0f, 0.006f, 0.47f, 0.473f, -0.86f, 0.0f, 0.003f, 0.468f, 0.473f,
+ -0.855f, 0.0f, 0.001f, 0.466f, 0.469f, -0.85f, 0.0f, 0.001f, 0.463f, 0.469f, -0.846f, 0.0f, 0.003f, 0.46f, 0.45f, -0.843f, 0.0f, 0.008f, 0.458f, 0.454f,
+ -0.84f, 0.0f, 0.014f, 0.456f, 0.454f, -0.838f, 0.0f, 0.021f, 0.455f, 0.454f, -0.836f, 0.0f, 0.03f, 0.453f, 0.455f, -0.835f, 0.0f, 0.039f, 0.451f, 0.455f,
+ -0.835f, 0.0f, 0.049f, 0.449f, 0.453f, -0.836f, 0.0f, 0.059f, 0.447f, 0.445f, -0.837f, 0.0f, 0.068f, 0.445f, 0.441f, -0.84f, 0.0f, 0.078f, 0.443f, 0.44f,
+ -0.843f, 0.0f, 0.087f, 0.442f, 0.44f, -0.846f, 0.0f, 0.095f, 0.442f, 0.44f, -0.851f, -0.0f, 0.103f, 0.441f, 0.441f, -0.855f, -0.0f, 0.111f, 0.441f, 0.44f,
+ -0.86f, -0.0f, 0.119f, 0.441f, 0.441f, -0.865f, -0.0f, 0.127f, 0.441f, 0.441f, -0.871f, -0.0f, 0.134f, 0.441f, 0.441f, -0.877f, -0.0f, 0.141f, 0.441f, 0.441f,
+ -0.883f, -0.0f, 0.149f, 0.441f, 0.442f, -0.889f, -0.0f, 0.156f, 0.441f, 0.441f, -0.896f, -0.0f, 0.163f, 0.441f, 0.442f, -0.904f, -0.0f, 0.169f, 0.442f, 0.441f,
+ -0.913f, -0.0f, 0.176f, 0.442f, 0.441f, -0.925f, -0.0f, 0.183f, 0.443f, 0.441f, -0.941f, -0.0f, 0.19f, 0.444f, 0.442f, -0.956f, -0.0f, 0.195f, 0.446f, 0.443f,
+ -0.971f, -0.0f, 0.198f, 0.448f, 0.443f, -0.983f, -0.0f, 0.198f, 0.451f, 0.452f, -0.992f, -0.0f, 0.198f, 0.454f, 0.456f, -1.001f, 0.0f, 0.196f, 0.457f, 0.457f,
+};
+
+static const float data18[59 * GP_PRIM_DATABUF_SIZE] = {
+ 0.782f, 0.0f, 0.099f, 0.04f, 0.04f, 0.779f, 0.0f, 0.088f, 0.108f, 0.34f, 0.777f, 0.0f, 0.08f, 0.149f, 0.35f, 0.774f, 0.0f, 0.071f, 0.194f, 0.352f,
+ 0.772f, 0.0f, 0.062f, 0.231f, 0.352f, 0.771f, 0.0f, 0.053f, 0.263f, 0.353f, 0.769f, 0.0f, 0.044f, 0.289f, 0.353f, 0.768f, 0.0f, 0.036f, 0.31f, 0.353f,
+ 0.767f, 0.0f, 0.029f, 0.327f, 0.353f, 0.767f, 0.0f, 0.023f, 0.341f, 0.353f, 0.767f, 0.0f, 0.017f, 0.353f, 0.353f, 0.768f, 0.0f, 0.013f, 0.363f, 0.353f,
+ 0.769f, 0.0f, 0.01f, 0.373f, 0.353f, 0.771f, 0.0f, 0.009f, 0.382f, 0.351f, 0.773f, 0.0f, 0.008f, 0.39f, 0.393f, 0.776f, 0.0f, 0.009f, 0.399f, 0.41f,
+ 0.779f, 0.0f, 0.011f, 0.407f, 0.425f, 0.783f, 0.0f, 0.015f, 0.415f, 0.434f, 0.787f, 0.0f, 0.019f, 0.423f, 0.44f, 0.792f, 0.0f, 0.024f, 0.429f, 0.441f,
+ 0.797f, 0.0f, 0.03f, 0.435f, 0.444f, 0.802f, 0.0f, 0.037f, 0.441f, 0.447f, 0.807f, 0.0f, 0.044f, 0.445f, 0.453f, 0.813f, 0.0f, 0.051f, 0.449f, 0.457f,
+ 0.819f, 0.0f, 0.058f, 0.452f, 0.458f, 0.825f, 0.0f, 0.066f, 0.455f, 0.46f, 0.831f, 0.0f, 0.074f, 0.457f, 0.462f, 0.838f, 0.0f, 0.082f, 0.459f, 0.462f,
+ 0.845f, 0.0f, 0.09f, 0.461f, 0.462f, 0.852f, 0.0f, 0.098f, 0.462f, 0.463f, 0.859f, 0.0f, 0.106f, 0.463f, 0.464f, 0.867f, 0.0f, 0.113f, 0.464f, 0.464f,
+ 0.874f, 0.0f, 0.121f, 0.465f, 0.465f, 0.882f, 0.0f, 0.129f, 0.465f, 0.465f, 0.889f, 0.0f, 0.136f, 0.466f, 0.466f, 0.897f, 0.0f, 0.143f, 0.466f, 0.467f,
+ 0.904f, 0.0f, 0.15f, 0.467f, 0.466f, 0.911f, 0.0f, 0.157f, 0.467f, 0.467f, 0.916f, 0.0f, 0.163f, 0.468f, 0.468f, 0.921f, 0.0f, 0.169f, 0.468f, 0.469f,
+ 0.924f, 0.0f, 0.173f, 0.468f, 0.469f, 0.926f, 0.0f, 0.177f, 0.469f, 0.468f, 0.925f, 0.0f, 0.18f, 0.469f, 0.468f, 0.922f, 0.0f, 0.181f, 0.469f, 0.469f,
+ 0.918f, 0.0f, 0.181f, 0.469f, 0.469f, 0.912f, 0.0f, 0.18f, 0.469f, 0.469f, 0.905f, 0.0f, 0.178f, 0.468f, 0.47f, 0.898f, 0.0f, 0.175f, 0.466f, 0.471f,
+ 0.89f, 0.0f, 0.172f, 0.462f, 0.469f, 0.882f, 0.0f, 0.168f, 0.454f, 0.468f, 0.874f, 0.0f, 0.164f, 0.442f, 0.467f, 0.866f, 0.0f, 0.159f, 0.423f, 0.467f,
+ 0.858f, 0.0f, 0.154f, 0.398f, 0.468f, 0.851f, 0.0f, 0.149f, 0.366f, 0.468f, 0.844f, 0.0f, 0.144f, 0.326f, 0.469f, 0.837f, 0.0f, 0.139f, 0.282f, 0.469f,
+ 0.83f, 0.0f, 0.134f, 0.231f, 0.467f, 0.824f, 0.0f, 0.13f, 0.184f, 0.415f, 0.816f, 0.0f, 0.124f, 0.111f, 0.111f,
+};
+
+static const float data19[100 * GP_PRIM_DATABUF_SIZE] = {
+ -0.279f, 0.0f, 0.568f, 0.154f, 0.154f, -0.266f, 0.0f, 0.569f, 0.249f, 0.318f, -0.258f, 0.0f, 0.57f, 0.296f, 0.357f, -0.248f, 0.0f, 0.571f, 0.337f, 0.383f,
+ -0.238f, 0.0f, 0.571f, 0.363f, 0.396f, -0.229f, 0.0f, 0.571f, 0.381f, 0.403f, -0.219f, 0.0f, 0.57f, 0.392f, 0.407f, -0.209f, 0.0f, 0.568f, 0.399f, 0.407f,
+ -0.2f, 0.0f, 0.566f, 0.403f, 0.408f, -0.19f, 0.0f, 0.563f, 0.406f, 0.41f, -0.181f, 0.0f, 0.559f, 0.407f, 0.41f, -0.171f, 0.0f, 0.555f, 0.409f, 0.41f,
+ -0.161f, 0.0f, 0.551f, 0.409f, 0.411f, -0.152f, 0.0f, 0.546f, 0.41f, 0.411f, -0.142f, 0.0f, 0.542f, 0.41f, 0.412f, -0.132f, 0.0f, 0.537f, 0.411f, 0.411f,
+ -0.122f, 0.0f, 0.533f, 0.411f, 0.411f, -0.112f, 0.0f, 0.528f, 0.411f, 0.412f, -0.102f, 0.0f, 0.524f, 0.411f, 0.412f, -0.092f, 0.0f, 0.519f, 0.41f, 0.412f,
+ -0.081f, 0.0f, 0.515f, 0.407f, 0.411f, -0.071f, 0.0f, 0.511f, 0.403f, 0.408f, -0.061f, 0.0f, 0.507f, 0.399f, 0.401f, -0.051f, 0.0f, 0.503f, 0.394f, 0.395f,
+ -0.041f, 0.0f, 0.499f, 0.39f, 0.388f, -0.031f, 0.0f, 0.495f, 0.386f, 0.383f, -0.021f, 0.0f, 0.491f, 0.383f, 0.38f, -0.011f, 0.0f, 0.488f, 0.381f, 0.378f,
+ -0.001f, 0.0f, 0.486f, 0.379f, 0.377f, 0.009f, 0.0f, 0.484f, 0.378f, 0.377f, 0.019f, 0.0f, 0.483f, 0.377f, 0.375f, 0.03f, 0.0f, 0.482f, 0.377f, 0.375f,
+ 0.041f, 0.0f, 0.482f, 0.378f, 0.376f, 0.051f, 0.0f, 0.483f, 0.379f, 0.376f, 0.062f, 0.0f, 0.484f, 0.381f, 0.376f, 0.073f, 0.0f, 0.486f, 0.385f, 0.379f,
+ 0.085f, 0.0f, 0.488f, 0.389f, 0.382f, 0.096f, 0.0f, 0.491f, 0.395f, 0.392f, 0.108f, 0.0f, 0.494f, 0.402f, 0.4f, 0.12f, 0.0f, 0.497f, 0.409f, 0.409f,
+ 0.132f, 0.0f, 0.501f, 0.415f, 0.416f, 0.144f, 0.0f, 0.505f, 0.421f, 0.427f, 0.157f, 0.0f, 0.509f, 0.425f, 0.43f, 0.17f, 0.0f, 0.513f, 0.429f, 0.433f,
+ 0.181f, 0.0f, 0.517f, 0.431f, 0.433f, 0.192f, 0.0f, 0.52f, 0.433f, 0.434f, 0.201f, 0.0f, 0.522f, 0.433f, 0.435f, 0.208f, 0.0f, 0.524f, 0.433f, 0.435f,
+ 0.213f, 0.0f, 0.524f, 0.432f, 0.436f, 0.216f, 0.0f, 0.523f, 0.431f, 0.435f, 0.217f, 0.0f, 0.521f, 0.43f, 0.426f, 0.215f, 0.0f, 0.518f, 0.429f, 0.427f,
+ 0.213f, 0.0f, 0.515f, 0.428f, 0.427f, 0.208f, 0.0f, 0.511f, 0.428f, 0.427f, 0.203f, 0.0f, 0.506f, 0.428f, 0.427f, 0.196f, 0.0f, 0.502f, 0.428f, 0.427f,
+ 0.189f, 0.0f, 0.497f, 0.428f, 0.427f, 0.181f, 0.0f, 0.492f, 0.428f, 0.427f, 0.173f, 0.0f, 0.487f, 0.428f, 0.428f, 0.163f, 0.0f, 0.482f, 0.429f, 0.428f,
+ 0.154f, 0.0f, 0.477f, 0.429f, 0.429f, 0.145f, 0.0f, 0.472f, 0.43f, 0.43f, 0.135f, 0.0f, 0.467f, 0.431f, 0.431f, 0.125f, 0.0f, 0.462f, 0.432f, 0.43f,
+ 0.116f, 0.0f, 0.457f, 0.433f, 0.431f, 0.106f, 0.0f, 0.453f, 0.435f, 0.434f, 0.096f, 0.0f, 0.448f, 0.436f, 0.436f, 0.086f, 0.0f, 0.444f, 0.437f, 0.438f,
+ 0.076f, 0.0f, 0.44f, 0.438f, 0.44f, 0.065f, 0.0f, 0.436f, 0.439f, 0.441f, 0.055f, 0.0f, 0.433f, 0.44f, 0.441f, 0.044f, 0.0f, 0.431f, 0.441f, 0.442f,
+ 0.033f, 0.0f, 0.429f, 0.441f, 0.442f, 0.022f, 0.0f, 0.427f, 0.441f, 0.442f, 0.011f, 0.0f, 0.426f, 0.442f, 0.443f, -0.0f, 0.0f, 0.426f, 0.442f, 0.442f,
+ -0.011f, 0.0f, 0.426f, 0.442f, 0.442f, -0.022f, 0.0f, 0.427f, 0.442f, 0.442f, -0.033f, 0.0f, 0.429f, 0.442f, 0.442f, -0.042f, 0.0f, 0.432f, 0.441f, 0.442f,
+ -0.052f, 0.0f, 0.435f, 0.441f, 0.441f, -0.061f, 0.0f, 0.439f, 0.441f, 0.441f, -0.07f, 0.0f, 0.443f, 0.441f, 0.441f, -0.078f, 0.0f, 0.448f, 0.441f, 0.441f,
+ -0.087f, 0.0f, 0.453f, 0.441f, 0.442f, -0.095f, 0.0f, 0.458f, 0.441f, 0.441f, -0.104f, 0.0f, 0.463f, 0.44f, 0.44f, -0.113f, 0.0f, 0.468f, 0.44f, 0.44f,
+ -0.122f, 0.0f, 0.473f, 0.44f, 0.44f, -0.132f, 0.0f, 0.479f, 0.44f, 0.44f, -0.143f, 0.0f, 0.485f, 0.44f, 0.44f, -0.154f, 0.0f, 0.491f, 0.44f, 0.44f,
+ -0.165f, 0.0f, 0.498f, 0.44f, 0.44f, -0.176f, 0.0f, 0.504f, 0.439f, 0.439f, -0.187f, 0.0f, 0.51f, 0.435f, 0.44f, -0.198f, 0.0f, 0.516f, 0.424f, 0.44f,
+ -0.209f, 0.0f, 0.522f, 0.393f, 0.44f, -0.219f, 0.0f, 0.527f, 0.324f, 0.44f, -0.228f, 0.0f, 0.532f, 0.222f, 0.404f, -0.241f, 0.0f, 0.538f, 0.037f, 0.037f,
+};
+
+static const float data20[136 * GP_PRIM_DATABUF_SIZE] = {
+ 0.331f, 0.0f, -0.036f, 0.065f, 0.065f, 0.322f, 0.0f, -0.034f, 0.239f, 0.293f, 0.317f, 0.0f, -0.032f, 0.316f, 0.339f, 0.31f, 0.0f, -0.029f, 0.348f, 0.355f,
+ 0.302f, 0.0f, -0.027f, 0.364f, 0.368f, 0.295f, 0.0f, -0.023f, 0.373f, 0.374f, 0.287f, 0.0f, -0.02f, 0.381f, 0.381f, 0.279f, 0.0f, -0.015f, 0.388f, 0.391f,
+ 0.271f, 0.0f, -0.01f, 0.392f, 0.394f, 0.263f, 0.0f, -0.004f, 0.395f, 0.396f, 0.255f, 0.0f, 0.002f, 0.397f, 0.397f, 0.247f, 0.0f, 0.008f, 0.399f, 0.4f,
+ 0.239f, 0.0f, 0.016f, 0.401f, 0.401f, 0.232f, -0.0f, 0.024f, 0.404f, 0.404f, 0.226f, 0.0f, 0.031f, 0.406f, 0.407f, 0.221f, 0.0f, 0.038f, 0.409f, 0.409f,
+ 0.215f, 0.0f, 0.045f, 0.412f, 0.412f, 0.21f, 0.0f, 0.054f, 0.415f, 0.415f, 0.205f, 0.0f, 0.063f, 0.417f, 0.417f, 0.201f, 0.0f, 0.073f, 0.42f, 0.421f,
+ 0.197f, 0.0f, 0.083f, 0.421f, 0.421f, 0.193f, -0.0f, 0.094f, 0.423f, 0.423f, 0.19f, -0.0f, 0.104f, 0.424f, 0.424f, 0.187f, -0.0f, 0.114f, 0.424f, 0.425f,
+ 0.185f, -0.0f, 0.125f, 0.425f, 0.425f, 0.183f, -0.0f, 0.135f, 0.425f, 0.425f, 0.182f, -0.0f, 0.146f, 0.426f, 0.425f, 0.181f, -0.0f, 0.157f, 0.426f, 0.425f,
+ 0.18f, -0.0f, 0.168f, 0.426f, 0.426f, 0.18f, -0.0f, 0.179f, 0.427f, 0.427f, 0.181f, -0.0f, 0.189f, 0.427f, 0.427f, 0.182f, -0.0f, 0.199f, 0.427f, 0.427f,
+ 0.183f, -0.0f, 0.208f, 0.427f, 0.428f, 0.185f, -0.0f, 0.218f, 0.428f, 0.427f, 0.187f, -0.0f, 0.226f, 0.428f, 0.427f, 0.19f, -0.0f, 0.235f, 0.429f, 0.427f,
+ 0.192f, -0.0f, 0.243f, 0.43f, 0.428f, 0.196f, -0.0f, 0.252f, 0.431f, 0.431f, 0.199f, -0.0f, 0.26f, 0.431f, 0.432f, 0.203f, -0.0f, 0.268f, 0.432f, 0.433f,
+ 0.207f, -0.0f, 0.276f, 0.433f, 0.433f, 0.212f, -0.0f, 0.283f, 0.434f, 0.434f, 0.216f, -0.0f, 0.291f, 0.434f, 0.435f, 0.221f, -0.0f, 0.298f, 0.435f, 0.436f,
+ 0.227f, -0.0f, 0.305f, 0.435f, 0.435f, 0.232f, -0.0f, 0.311f, 0.436f, 0.436f, 0.238f, -0.0f, 0.317f, 0.436f, 0.436f, 0.243f, -0.0f, 0.323f, 0.436f, 0.436f,
+ 0.249f, -0.0f, 0.329f, 0.437f, 0.436f, 0.255f, -0.0f, 0.334f, 0.438f, 0.437f, 0.262f, -0.0f, 0.339f, 0.44f, 0.437f, 0.268f, -0.0f, 0.344f, 0.442f, 0.441f,
+ 0.274f, 0.0f, 0.348f, 0.444f, 0.446f, 0.281f, 0.0f, 0.352f, 0.445f, 0.447f, 0.287f, 0.0f, 0.355f, 0.446f, 0.447f, 0.293f, 0.0f, 0.358f, 0.446f, 0.447f,
+ 0.299f, 0.0f, 0.361f, 0.447f, 0.447f, 0.306f, 0.0f, 0.363f, 0.447f, 0.448f, 0.312f, 0.0f, 0.366f, 0.447f, 0.448f, 0.318f, 0.0f, 0.368f, 0.448f, 0.448f,
+ 0.325f, 0.0f, 0.369f, 0.448f, 0.448f, 0.331f, 0.0f, 0.371f, 0.448f, 0.448f, 0.338f, 0.0f, 0.372f, 0.448f, 0.448f, 0.345f, 0.0f, 0.372f, 0.448f, 0.448f,
+ 0.352f, 0.0f, 0.372f, 0.448f, 0.448f, 0.359f, 0.0f, 0.372f, 0.448f, 0.449f, 0.366f, 0.0f, 0.371f, 0.448f, 0.448f, 0.373f, 0.0f, 0.37f, 0.448f, 0.449f,
+ 0.38f, 0.0f, 0.369f, 0.449f, 0.449f, 0.387f, 0.0f, 0.367f, 0.449f, 0.449f, 0.393f, 0.0f, 0.365f, 0.449f, 0.449f, 0.4f, 0.0f, 0.363f, 0.449f, 0.45f,
+ 0.406f, 0.0f, 0.36f, 0.45f, 0.45f, 0.412f, -0.0f, 0.357f, 0.45f, 0.45f, 0.418f, -0.0f, 0.354f, 0.45f, 0.451f, 0.424f, -0.0f, 0.351f, 0.45f, 0.451f,
+ 0.43f, -0.0f, 0.347f, 0.45f, 0.451f, 0.436f, -0.0f, 0.343f, 0.45f, 0.451f, 0.443f, -0.0f, 0.339f, 0.45f, 0.45f, 0.449f, -0.0f, 0.334f, 0.45f, 0.451f,
+ 0.455f, -0.0f, 0.329f, 0.451f, 0.451f, 0.46f, -0.0f, 0.323f, 0.451f, 0.451f, 0.466f, -0.0f, 0.318f, 0.451f, 0.451f, 0.472f, -0.0f, 0.311f, 0.452f, 0.452f,
+ 0.477f, -0.0f, 0.305f, 0.452f, 0.453f, 0.482f, -0.0f, 0.298f, 0.452f, 0.453f, 0.487f, -0.0f, 0.291f, 0.453f, 0.453f, 0.492f, -0.0f, 0.284f, 0.453f, 0.453f,
+ 0.496f, -0.0f, 0.277f, 0.453f, 0.453f, 0.5f, -0.0f, 0.269f, 0.453f, 0.454f, 0.504f, -0.0f, 0.261f, 0.453f, 0.454f, 0.508f, -0.0f, 0.252f, 0.454f, 0.454f,
+ 0.511f, -0.0f, 0.244f, 0.454f, 0.454f, 0.514f, -0.0f, 0.235f, 0.454f, 0.455f, 0.517f, -0.0f, 0.225f, 0.454f, 0.455f, 0.519f, -0.0f, 0.216f, 0.454f, 0.455f,
+ 0.521f, -0.0f, 0.205f, 0.455f, 0.455f, 0.523f, -0.0f, 0.194f, 0.455f, 0.455f, 0.524f, -0.0f, 0.182f, 0.455f, 0.455f, 0.524f, -0.0f, 0.169f, 0.455f, 0.456f,
+ 0.524f, -0.0f, 0.157f, 0.455f, 0.456f, 0.523f, -0.0f, 0.145f, 0.455f, 0.456f, 0.522f, -0.0f, 0.133f, 0.455f, 0.456f, 0.52f, -0.0f, 0.122f, 0.456f, 0.456f,
+ 0.518f, -0.0f, 0.11f, 0.456f, 0.456f, 0.515f, -0.0f, 0.1f, 0.456f, 0.456f, 0.513f, -0.0f, 0.09f, 0.456f, 0.457f, 0.509f, -0.0f, 0.081f, 0.456f, 0.457f,
+ 0.506f, -0.0f, 0.072f, 0.457f, 0.457f, 0.502f, -0.0f, 0.064f, 0.457f, 0.457f, 0.498f, -0.0f, 0.056f, 0.457f, 0.457f, 0.494f, -0.0f, 0.049f, 0.457f, 0.457f,
+ 0.49f, -0.0f, 0.041f, 0.458f, 0.457f, 0.485f, -0.0f, 0.034f, 0.458f, 0.457f, 0.48f, -0.0f, 0.028f, 0.458f, 0.458f, 0.475f, -0.0f, 0.022f, 0.458f, 0.458f,
+ 0.47f, -0.0f, 0.016f, 0.458f, 0.458f, 0.465f, -0.0f, 0.011f, 0.459f, 0.458f, 0.46f, -0.0f, 0.006f, 0.459f, 0.458f, 0.454f, -0.0f, 0.001f, 0.46f, 0.459f,
+ 0.449f, 0.0f, -0.003f, 0.464f, 0.463f, 0.443f, 0.0f, -0.007f, 0.467f, 0.468f, 0.438f, 0.0f, -0.011f, 0.469f, 0.469f, 0.432f, 0.0f, -0.015f, 0.471f, 0.47f,
+ 0.426f, 0.0f, -0.018f, 0.477f, 0.478f, 0.42f, 0.0f, -0.021f, 0.478f, 0.478f, 0.414f, 0.0f, -0.024f, 0.478f, 0.478f, 0.408f, 0.0f, -0.027f, 0.479f, 0.479f,
+ 0.402f, 0.0f, -0.029f, 0.48f, 0.48f, 0.395f, 0.0f, -0.031f, 0.48f, 0.48f, 0.389f, 0.0f, -0.033f, 0.482f, 0.482f, 0.382f, 0.0f, -0.035f, 0.482f, 0.482f,
+ 0.376f, 0.0f, -0.036f, 0.482f, 0.482f, 0.369f, 0.0f, -0.037f, 0.48f, 0.482f, 0.364f, 0.0f, -0.037f, 0.457f, 0.485f, 0.356f, 0.0f, -0.038f, 0.32f, 0.32f,
+};
+
+static const float data21[353 * GP_PRIM_DATABUF_SIZE] = {
+ -0.382f, 0.0f, 0.397f, 0.0f, 1.0f, -0.386f, 0.0f, 0.394f, 0.0f, 1.0f, -0.389f, 0.0f, 0.392f, 0.0f, 1.0f, -0.392f, 0.0f, 0.39f, 0.0f, 1.0f,
+ -0.395f, 0.0f, 0.388f, 0.0f, 1.0f, -0.399f, 0.0f, 0.385f, 0.0f, 1.0f, -0.402f, 0.0f, 0.383f, 0.0f, 1.0f, -0.405f, 0.0f, 0.381f, 0.0f, 1.0f,
+ -0.408f, 0.0f, 0.379f, 0.0f, 1.0f, -0.411f, 0.0f, 0.377f, 0.0f, 1.0f, -0.414f, 0.0f, 0.375f, 0.0f, 1.0f, -0.417f, 0.0f, 0.372f, 0.0f, 1.0f,
+ -0.42f, 0.0f, 0.37f, 0.0f, 1.0f, -0.423f, 0.0f, 0.368f, 0.0f, 1.0f, -0.425f, 0.0f, 0.366f, 0.0f, 1.0f, -0.428f, 0.0f, 0.364f, 0.0f, 1.0f,
+ -0.431f, 0.0f, 0.362f, 0.0f, 1.0f, -0.433f, 0.0f, 0.359f, 0.0f, 1.0f, -0.436f, 0.0f, 0.357f, 0.0f, 1.0f, -0.438f, 0.0f, 0.355f, 0.0f, 1.0f,
+ -0.441f, 0.0f, 0.353f, 0.0f, 1.0f, -0.443f, 0.0f, 0.351f, 0.0f, 1.0f, -0.445f, 0.0f, 0.349f, 0.0f, 1.0f, -0.447f, 0.0f, 0.346f, 0.0f, 1.0f,
+ -0.45f, 0.0f, 0.344f, 0.0f, 1.0f, -0.452f, 0.0f, 0.342f, 0.0f, 1.0f, -0.454f, 0.0f, 0.34f, 0.0f, 1.0f, -0.456f, 0.0f, 0.337f, 0.0f, 1.0f,
+ -0.458f, 0.0f, 0.335f, 0.0f, 1.0f, -0.46f, 0.0f, 0.333f, 0.0f, 1.0f, -0.462f, 0.0f, 0.33f, 0.0f, 1.0f, -0.464f, 0.0f, 0.328f, 0.0f, 1.0f,
+ -0.466f, 0.0f, 0.326f, 0.0f, 1.0f, -0.468f, 0.0f, 0.323f, 0.0f, 1.0f, -0.47f, 0.0f, 0.321f, 0.0f, 1.0f, -0.472f, 0.0f, 0.319f, 0.0f, 1.0f,
+ -0.474f, 0.0f, 0.316f, 0.0f, 1.0f, -0.475f, 0.0f, 0.314f, 0.0f, 1.0f, -0.477f, 0.0f, 0.311f, 0.0f, 1.0f, -0.479f, 0.0f, 0.309f, 0.0f, 1.0f,
+ -0.481f, 0.0f, 0.307f, 0.0f, 1.0f, -0.482f, 0.0f, 0.304f, 0.0f, 1.0f, -0.484f, 0.0f, 0.302f, 0.0f, 1.0f, -0.486f, 0.0f, 0.299f, 0.0f, 1.0f,
+ -0.487f, 0.0f, 0.297f, 0.0f, 1.0f, -0.489f, 0.0f, 0.294f, 0.0f, 1.0f, -0.49f, 0.0f, 0.292f, 0.0f, 1.0f, -0.492f, 0.0f, 0.289f, 0.0f, 1.0f,
+ -0.494f, 0.0f, 0.286f, 0.0f, 1.0f, -0.495f, 0.0f, 0.284f, 0.0f, 1.0f, -0.497f, 0.0f, 0.281f, 0.0f, 1.0f, -0.498f, 0.0f, 0.279f, 0.001f, 1.0f,
+ -0.499f, 0.0f, 0.276f, 0.001f, 1.0f, -0.501f, 0.0f, 0.273f, 0.002f, 1.0f, -0.502f, 0.0f, 0.271f, 0.003f, 1.0f, -0.504f, 0.0f, 0.268f, 0.005f, 1.0f,
+ -0.505f, 0.0f, 0.265f, 0.008f, 1.0f, -0.506f, 0.0f, 0.262f, 0.011f, 1.0f, -0.508f, 0.0f, 0.259f, 0.016f, 1.0f, -0.509f, 0.0f, 0.256f, 0.021f, 1.0f,
+ -0.51f, 0.0f, 0.254f, 0.027f, 1.0f, -0.512f, 0.0f, 0.251f, 0.035f, 1.0f, -0.513f, 0.0f, 0.248f, 0.043f, 1.0f, -0.514f, 0.0f, 0.245f, 0.053f, 1.0f,
+ -0.515f, 0.0f, 0.242f, 0.064f, 1.0f, -0.516f, 0.0f, 0.239f, 0.076f, 1.0f, -0.517f, 0.0f, 0.235f, 0.09f, 1.0f, -0.519f, 0.0f, 0.232f, 0.105f, 1.0f,
+ -0.52f, 0.0f, 0.229f, 0.122f, 1.0f, -0.521f, 0.0f, 0.226f, 0.14f, 1.0f, -0.521f, 0.0f, 0.222f, 0.159f, 1.0f, -0.522f, 0.0f, 0.219f, 0.179f, 1.0f,
+ -0.523f, 0.0f, 0.216f, 0.2f, 1.0f, -0.524f, 0.0f, 0.212f, 0.221f, 1.0f, -0.525f, 0.0f, 0.209f, 0.243f, 1.0f, -0.526f, 0.0f, 0.205f, 0.265f, 1.0f,
+ -0.526f, 0.0f, 0.202f, 0.286f, 1.0f, -0.527f, 0.0f, 0.198f, 0.306f, 1.0f, -0.527f, 0.0f, 0.195f, 0.326f, 1.0f, -0.528f, 0.0f, 0.191f, 0.345f, 1.0f,
+ -0.528f, 0.0f, 0.187f, 0.363f, 1.0f, -0.529f, 0.0f, 0.184f, 0.38f, 1.0f, -0.529f, 0.0f, 0.18f, 0.395f, 1.0f, -0.529f, 0.0f, 0.176f, 0.41f, 1.0f,
+ -0.53f, 0.0f, 0.173f, 0.424f, 1.0f, -0.53f, 0.0f, 0.169f, 0.438f, 1.0f, -0.53f, 0.0f, 0.165f, 0.452f, 1.0f, -0.53f, 0.0f, 0.161f, 0.465f, 1.0f,
+ -0.53f, 0.0f, 0.157f, 0.478f, 1.0f, -0.53f, 0.0f, 0.154f, 0.492f, 1.0f, -0.53f, 0.0f, 0.15f, 0.505f, 1.0f, -0.53f, 0.0f, 0.146f, 0.517f, 1.0f,
+ -0.53f, 0.0f, 0.142f, 0.53f, 1.0f, -0.529f, 0.0f, 0.138f, 0.542f, 1.0f, -0.529f, 0.0f, 0.134f, 0.553f, 1.0f, -0.528f, 0.0f, 0.13f, 0.564f, 1.0f,
+ -0.528f, 0.0f, 0.127f, 0.574f, 1.0f, -0.527f, 0.0f, 0.123f, 0.583f, 1.0f, -0.527f, 0.0f, 0.119f, 0.592f, 1.0f, -0.526f, 0.0f, 0.115f, 0.6f, 1.0f,
+ -0.526f, 0.0f, 0.111f, 0.608f, 1.0f, -0.525f, 0.0f, 0.108f, 0.615f, 1.0f, -0.524f, 0.0f, 0.104f, 0.622f, 1.0f, -0.523f, 0.0f, 0.1f, 0.628f, 1.0f,
+ -0.522f, 0.0f, 0.097f, 0.635f, 1.0f, -0.521f, 0.0f, 0.093f, 0.641f, 1.0f, -0.52f, 0.0f, 0.089f, 0.647f, 1.0f, -0.519f, 0.0f, 0.086f, 0.653f, 1.0f,
+ -0.518f, 0.0f, 0.082f, 0.659f, 1.0f, -0.517f, 0.0f, 0.079f, 0.664f, 1.0f, -0.515f, 0.0f, 0.075f, 0.67f, 1.0f, -0.514f, 0.0f, 0.072f, 0.675f, 1.0f,
+ -0.513f, 0.0f, 0.069f, 0.68f, 1.0f, -0.511f, 0.0f, 0.065f, 0.685f, 1.0f, -0.51f, 0.0f, 0.062f, 0.69f, 1.0f, -0.509f, 0.0f, 0.059f, 0.695f, 1.0f,
+ -0.507f, 0.0f, 0.056f, 0.7f, 1.0f, -0.505f, 0.0f, 0.053f, 0.704f, 1.0f, -0.504f, 0.0f, 0.049f, 0.709f, 1.0f, -0.502f, 0.0f, 0.046f, 0.714f, 1.0f,
+ -0.5f, 0.0f, 0.043f, 0.719f, 1.0f, -0.499f, 0.0f, 0.04f, 0.724f, 1.0f, -0.497f, 0.0f, 0.038f, 0.73f, 1.0f, -0.495f, 0.0f, 0.035f, 0.735f, 1.0f,
+ -0.493f, 0.0f, 0.032f, 0.741f, 1.0f, -0.491f, 0.0f, 0.029f, 0.748f, 1.0f, -0.489f, 0.0f, 0.026f, 0.754f, 1.0f, -0.488f, -0.0f, 0.024f, 0.76f, 1.0f,
+ -0.486f, -0.0f, 0.022f, 0.767f, 1.0f, -0.485f, -0.0f, 0.019f, 0.773f, 1.0f, -0.483f, -0.0f, 0.017f, 0.779f, 1.0f, -0.482f, -0.0f, 0.015f, 0.785f, 1.0f,
+ -0.48f, -0.0f, 0.013f, 0.79f, 1.0f, -0.478f, -0.0f, 0.01f, 0.795f, 1.0f, -0.476f, -0.0f, 0.008f, 0.8f, 1.0f, -0.474f, -0.0f, 0.006f, 0.804f, 1.0f,
+ -0.472f, -0.0f, 0.004f, 0.808f, 1.0f, -0.47f, -0.0f, 0.002f, 0.811f, 1.0f, -0.468f, -0.0f, -0.0f, 0.814f, 1.0f, -0.466f, -0.0f, -0.002f, 0.816f, 1.0f,
+ -0.464f, -0.0f, -0.004f, 0.818f, 1.0f, -0.461f, -0.0f, -0.006f, 0.82f, 1.0f, -0.459f, -0.0f, -0.008f, 0.822f, 1.0f, -0.456f, -0.0f, -0.01f, 0.823f, 1.0f,
+ -0.454f, -0.0f, -0.012f, 0.825f, 1.0f, -0.451f, -0.0f, -0.014f, 0.826f, 1.0f, -0.448f, -0.0f, -0.016f, 0.827f, 1.0f, -0.445f, -0.0f, -0.018f, 0.828f, 1.0f,
+ -0.442f, -0.0f, -0.02f, 0.829f, 1.0f, -0.439f, -0.0f, -0.022f, 0.829f, 1.0f, -0.436f, -0.0f, -0.024f, 0.83f, 1.0f, -0.433f, -0.0f, -0.026f, 0.83f, 1.0f,
+ -0.43f, -0.0f, -0.027f, 0.83f, 1.0f, -0.426f, -0.0f, -0.029f, 0.83f, 1.0f, -0.423f, 0.0f, -0.031f, 0.83f, 1.0f, -0.42f, 0.0f, -0.032f, 0.83f, 1.0f,
+ -0.417f, 0.0f, -0.033f, 0.831f, 1.0f, -0.414f, 0.0f, -0.034f, 0.831f, 1.0f, -0.411f, 0.0f, -0.035f, 0.831f, 1.0f, -0.408f, 0.0f, -0.037f, 0.831f, 1.0f,
+ -0.405f, 0.0f, -0.038f, 0.831f, 1.0f, -0.402f, 0.0f, -0.039f, 0.831f, 1.0f, -0.399f, 0.0f, -0.039f, 0.831f, 1.0f, -0.396f, 0.0f, -0.04f, 0.832f, 1.0f,
+ -0.393f, 0.0f, -0.041f, 0.832f, 1.0f, -0.389f, 0.0f, -0.042f, 0.832f, 1.0f, -0.386f, 0.0f, -0.043f, 0.832f, 1.0f, -0.383f, 0.0f, -0.044f, 0.832f, 1.0f,
+ -0.379f, 0.0f, -0.044f, 0.832f, 1.0f, -0.376f, 0.0f, -0.045f, 0.832f, 1.0f, -0.372f, 0.0f, -0.045f, 0.832f, 1.0f, -0.369f, 0.0f, -0.046f, 0.832f, 1.0f,
+ -0.366f, 0.0f, -0.047f, 0.832f, 1.0f, -0.362f, 0.0f, -0.047f, 0.832f, 1.0f, -0.359f, 0.0f, -0.047f, 0.831f, 1.0f, -0.355f, 0.0f, -0.048f, 0.831f, 1.0f,
+ -0.352f, 0.0f, -0.048f, 0.83f, 1.0f, -0.348f, 0.0f, -0.048f, 0.83f, 1.0f, -0.345f, 0.0f, -0.049f, 0.829f, 1.0f, -0.341f, 0.0f, -0.049f, 0.828f, 1.0f,
+ -0.338f, 0.0f, -0.049f, 0.827f, 1.0f, -0.334f, 0.0f, -0.049f, 0.826f, 1.0f, -0.331f, 0.0f, -0.049f, 0.823f, 1.0f, -0.327f, 0.0f, -0.049f, 0.82f, 1.0f,
+ -0.323f, 0.0f, -0.048f, 0.816f, 1.0f, -0.32f, 0.0f, -0.048f, 0.811f, 1.0f, -0.316f, 0.0f, -0.048f, 0.804f, 1.0f, -0.313f, 0.0f, -0.048f, 0.797f, 1.0f,
+ -0.309f, 0.0f, -0.047f, 0.79f, 1.0f, -0.306f, 0.0f, -0.047f, 0.782f, 1.0f, -0.302f, 0.0f, -0.046f, 0.774f, 1.0f, -0.299f, 0.0f, -0.045f, 0.767f, 1.0f,
+ -0.295f, 0.0f, -0.044f, 0.76f, 1.0f, -0.292f, 0.0f, -0.044f, 0.753f, 1.0f, -0.288f, 0.0f, -0.043f, 0.748f, 1.0f, -0.285f, 0.0f, -0.042f, 0.742f, 1.0f,
+ -0.282f, 0.0f, -0.041f, 0.738f, 1.0f, -0.278f, 0.0f, -0.04f, 0.734f, 1.0f, -0.275f, 0.0f, -0.039f, 0.73f, 1.0f, -0.272f, 0.0f, -0.037f, 0.726f, 1.0f,
+ -0.269f, 0.0f, -0.036f, 0.723f, 1.0f, -0.266f, 0.0f, -0.035f, 0.72f, 1.0f, -0.263f, 0.0f, -0.034f, 0.717f, 1.0f, -0.26f, 0.0f, -0.032f, 0.713f, 1.0f,
+ -0.257f, 0.0f, -0.031f, 0.71f, 1.0f, -0.255f, 0.0f, -0.029f, 0.706f, 1.0f, -0.252f, 0.0f, -0.028f, 0.702f, 1.0f, -0.249f, 0.0f, -0.026f, 0.698f, 1.0f,
+ -0.247f, 0.0f, -0.025f, 0.693f, 1.0f, -0.244f, 0.0f, -0.023f, 0.688f, 1.0f, -0.242f, 0.0f, -0.021f, 0.684f, 1.0f, -0.239f, 0.0f, -0.02f, 0.679f, 1.0f,
+ -0.237f, 0.0f, -0.018f, 0.675f, 1.0f, -0.234f, 0.0f, -0.016f, 0.671f, 1.0f, -0.232f, 0.0f, -0.014f, 0.667f, 1.0f, -0.23f, 0.0f, -0.013f, 0.663f, 1.0f,
+ -0.228f, 0.0f, -0.011f, 0.66f, 1.0f, -0.225f, 0.0f, -0.009f, 0.657f, 1.0f, -0.223f, 0.0f, -0.007f, 0.654f, 1.0f, -0.221f, 0.0f, -0.005f, 0.651f, 1.0f,
+ -0.219f, 0.0f, -0.003f, 0.649f, 1.0f, -0.217f, 0.0f, -0.001f, 0.645f, 1.0f, -0.215f, 0.0f, 0.002f, 0.642f, 1.0f, -0.213f, 0.0f, 0.004f, 0.639f, 1.0f,
+ -0.211f, 0.0f, 0.006f, 0.635f, 1.0f, -0.209f, 0.0f, 0.008f, 0.631f, 1.0f, -0.207f, 0.0f, 0.011f, 0.627f, 1.0f, -0.206f, 0.0f, 0.013f, 0.623f, 1.0f,
+ -0.204f, 0.0f, 0.016f, 0.619f, 1.0f, -0.202f, 0.0f, 0.018f, 0.615f, 1.0f, -0.2f, 0.0f, 0.021f, 0.61f, 1.0f, -0.199f, 0.0f, 0.023f, 0.606f, 1.0f,
+ -0.197f, 0.0f, 0.026f, 0.602f, 1.0f, -0.195f, 0.0f, 0.029f, 0.598f, 1.0f, -0.194f, 0.0f, 0.032f, 0.595f, 1.0f, -0.192f, 0.0f, 0.034f, 0.592f, 1.0f,
+ -0.191f, 0.0f, 0.037f, 0.589f, 1.0f, -0.19f, 0.0f, 0.04f, 0.587f, 1.0f, -0.188f, 0.0f, 0.043f, 0.585f, 1.0f, -0.187f, 0.0f, 0.046f, 0.584f, 1.0f,
+ -0.186f, 0.0f, 0.05f, 0.583f, 1.0f, -0.185f, 0.0f, 0.053f, 0.582f, 1.0f, -0.183f, 0.0f, 0.056f, 0.581f, 1.0f, -0.182f, 0.0f, 0.059f, 0.581f, 1.0f,
+ -0.181f, 0.0f, 0.062f, 0.581f, 1.0f, -0.18f, 0.0f, 0.066f, 0.581f, 1.0f, -0.179f, 0.0f, 0.069f, 0.58f, 1.0f, -0.178f, 0.0f, 0.072f, 0.58f, 1.0f,
+ -0.177f, 0.0f, 0.076f, 0.58f, 1.0f, -0.177f, 0.0f, 0.079f, 0.58f, 1.0f, -0.176f, 0.0f, 0.083f, 0.58f, 1.0f, -0.175f, 0.0f, 0.086f, 0.58f, 1.0f,
+ -0.174f, 0.0f, 0.09f, 0.58f, 1.0f, -0.174f, 0.0f, 0.093f, 0.58f, 1.0f, -0.173f, 0.0f, 0.097f, 0.58f, 1.0f, -0.172f, 0.0f, 0.1f, 0.58f, 1.0f,
+ -0.172f, 0.0f, 0.104f, 0.58f, 1.0f, -0.171f, 0.0f, 0.108f, 0.579f, 1.0f, -0.171f, 0.0f, 0.111f, 0.579f, 1.0f, -0.17f, 0.0f, 0.115f, 0.578f, 1.0f,
+ -0.17f, 0.0f, 0.119f, 0.578f, 1.0f, -0.17f, 0.0f, 0.122f, 0.577f, 1.0f, -0.169f, 0.0f, 0.126f, 0.577f, 1.0f, -0.169f, 0.0f, 0.13f, 0.576f, 1.0f,
+ -0.169f, 0.0f, 0.134f, 0.576f, 1.0f, -0.169f, 0.0f, 0.137f, 0.575f, 1.0f, -0.169f, 0.0f, 0.141f, 0.575f, 1.0f, -0.169f, 0.0f, 0.145f, 0.574f, 1.0f,
+ -0.169f, 0.0f, 0.149f, 0.572f, 1.0f, -0.169f, 0.0f, 0.153f, 0.571f, 1.0f, -0.169f, 0.0f, 0.157f, 0.569f, 1.0f, -0.169f, 0.0f, 0.16f, 0.566f, 1.0f,
+ -0.169f, 0.0f, 0.164f, 0.562f, 1.0f, -0.17f, 0.0f, 0.168f, 0.558f, 1.0f, -0.17f, 0.0f, 0.172f, 0.553f, 1.0f, -0.17f, 0.0f, 0.176f, 0.547f, 1.0f,
+ -0.171f, 0.0f, 0.18f, 0.539f, 1.0f, -0.171f, 0.0f, 0.183f, 0.531f, 1.0f, -0.172f, 0.0f, 0.187f, 0.522f, 1.0f, -0.172f, 0.0f, 0.191f, 0.513f, 1.0f,
+ -0.173f, 0.0f, 0.194f, 0.503f, 1.0f, -0.173f, 0.0f, 0.198f, 0.493f, 1.0f, -0.174f, 0.0f, 0.202f, 0.483f, 1.0f, -0.175f, 0.0f, 0.205f, 0.473f, 1.0f,
+ -0.176f, 0.0f, 0.209f, 0.464f, 1.0f, -0.177f, 0.0f, 0.212f, 0.455f, 1.0f, -0.178f, 0.0f, 0.215f, 0.446f, 1.0f, -0.178f, 0.0f, 0.219f, 0.438f, 1.0f,
+ -0.179f, 0.0f, 0.222f, 0.428f, 1.0f, -0.18f, 0.0f, 0.226f, 0.418f, 1.0f, -0.182f, 0.0f, 0.229f, 0.407f, 1.0f, -0.183f, 0.0f, 0.232f, 0.394f, 1.0f,
+ -0.184f, 0.0f, 0.236f, 0.38f, 1.0f, -0.185f, 0.0f, 0.239f, 0.364f, 1.0f, -0.186f, 0.0f, 0.242f, 0.348f, 1.0f, -0.187f, 0.0f, 0.245f, 0.33f, 1.0f,
+ -0.188f, 0.0f, 0.249f, 0.311f, 1.0f, -0.19f, 0.0f, 0.252f, 0.293f, 1.0f, -0.191f, 0.0f, 0.255f, 0.275f, 1.0f, -0.192f, 0.0f, 0.258f, 0.258f, 1.0f,
+ -0.194f, 0.0f, 0.261f, 0.242f, 1.0f, -0.195f, 0.0f, 0.264f, 0.228f, 1.0f, -0.196f, 0.0f, 0.267f, 0.214f, 1.0f, -0.198f, 0.0f, 0.27f, 0.202f, 1.0f,
+ -0.199f, 0.0f, 0.273f, 0.191f, 1.0f, -0.201f, 0.0f, 0.276f, 0.181f, 1.0f, -0.202f, 0.0f, 0.279f, 0.171f, 1.0f, -0.204f, 0.0f, 0.282f, 0.162f, 1.0f,
+ -0.205f, 0.0f, 0.285f, 0.152f, 1.0f, -0.206f, 0.0f, 0.287f, 0.143f, 1.0f, -0.208f, 0.0f, 0.29f, 0.134f, 1.0f, -0.21f, 0.0f, 0.293f, 0.126f, 1.0f,
+ -0.211f, 0.0f, 0.295f, 0.117f, 1.0f, -0.213f, 0.0f, 0.298f, 0.109f, 1.0f, -0.214f, 0.0f, 0.301f, 0.101f, 1.0f, -0.216f, 0.0f, 0.303f, 0.094f, 1.0f,
+ -0.217f, 0.0f, 0.306f, 0.087f, 1.0f, -0.219f, 0.0f, 0.308f, 0.081f, 1.0f, -0.221f, 0.0f, 0.311f, 0.076f, 1.0f, -0.223f, 0.0f, 0.313f, 0.071f, 1.0f,
+ -0.224f, 0.0f, 0.316f, 0.067f, 1.0f, -0.226f, 0.0f, 0.318f, 0.065f, 1.0f, -0.228f, 0.0f, 0.321f, 0.062f, 1.0f, -0.23f, 0.0f, 0.323f, 0.061f, 1.0f,
+ -0.232f, 0.0f, 0.326f, 0.06f, 1.0f, -0.233f, 0.0f, 0.328f, 0.06f, 1.0f, -0.235f, 0.0f, 0.331f, 0.061f, 1.0f, -0.237f, 0.0f, 0.334f, 0.061f, 1.0f,
+ -0.239f, 0.0f, 0.336f, 0.062f, 1.0f, -0.241f, 0.0f, 0.339f, 0.063f, 1.0f, -0.243f, 0.0f, 0.341f, 0.064f, 1.0f, -0.245f, 0.0f, 0.344f, 0.065f, 1.0f,
+ -0.248f, 0.0f, 0.346f, 0.065f, 1.0f, -0.25f, 0.0f, 0.349f, 0.065f, 1.0f, -0.252f, 0.0f, 0.351f, 0.064f, 1.0f, -0.254f, 0.0f, 0.354f, 0.062f, 1.0f,
+ -0.256f, 0.0f, 0.356f, 0.06f, 1.0f, -0.258f, 0.0f, 0.359f, 0.058f, 1.0f, -0.261f, 0.0f, 0.361f, 0.055f, 1.0f, -0.263f, 0.0f, 0.364f, 0.051f, 1.0f,
+ -0.265f, 0.0f, 0.366f, 0.046f, 1.0f, -0.267f, 0.0f, 0.368f, 0.04f, 1.0f, -0.269f, 0.0f, 0.37f, 0.034f, 1.0f, -0.272f, 0.0f, 0.373f, 0.027f, 1.0f,
+ -0.274f, 0.0f, 0.375f, 0.019f, 1.0f, -0.276f, 0.0f, 0.377f, 0.012f, 1.0f, -0.278f, 0.0f, 0.379f, 0.007f, 1.0f, -0.28f, 0.0f, 0.381f, 0.003f, 1.0f,
+ -0.282f, 0.0f, 0.383f, 0.001f, 1.0f, -0.284f, 0.0f, 0.385f, 0.0f, 1.0f, -0.286f, 0.0f, 0.387f, 0.0f, 1.0f, -0.287f, 0.0f, 0.388f, 0.0f, 1.0f,
+ -0.289f, 0.0f, 0.39f, 0.0f, 1.0f,
+};
+
+static const float data22[309 * GP_PRIM_DATABUF_SIZE] = {
+ 0.294f, 0.0f, 0.372f, 0.0f, 1.0f, 0.291f, 0.0f, 0.37f, 0.001f, 1.0f, 0.289f, 0.0f, 0.368f, 0.002f, 1.0f, 0.286f, 0.0f, 0.366f, 0.003f, 1.0f,
+ 0.284f, 0.0f, 0.364f, 0.006f, 1.0f, 0.282f, 0.0f, 0.362f, 0.01f, 1.0f, 0.279f, 0.0f, 0.36f, 0.015f, 1.0f, 0.277f, 0.0f, 0.358f, 0.022f, 1.0f,
+ 0.274f, 0.0f, 0.356f, 0.03f, 1.0f, 0.272f, 0.0f, 0.353f, 0.04f, 1.0f, 0.269f, 0.0f, 0.351f, 0.051f, 1.0f, 0.267f, 0.0f, 0.349f, 0.062f, 1.0f,
+ 0.265f, 0.0f, 0.347f, 0.074f, 1.0f, 0.262f, 0.0f, 0.344f, 0.086f, 1.0f, 0.26f, 0.0f, 0.342f, 0.097f, 1.0f, 0.258f, 0.0f, 0.34f, 0.108f, 1.0f,
+ 0.256f, 0.0f, 0.337f, 0.119f, 1.0f, 0.253f, 0.0f, 0.335f, 0.128f, 1.0f, 0.251f, 0.0f, 0.333f, 0.137f, 1.0f, 0.249f, 0.0f, 0.33f, 0.145f, 1.0f,
+ 0.247f, 0.0f, 0.328f, 0.153f, 1.0f, 0.246f, 0.0f, 0.325f, 0.161f, 1.0f, 0.244f, 0.0f, 0.323f, 0.168f, 1.0f, 0.242f, 0.0f, 0.321f, 0.176f, 1.0f,
+ 0.24f, 0.0f, 0.318f, 0.183f, 1.0f, 0.239f, 0.0f, 0.316f, 0.191f, 1.0f, 0.237f, 0.0f, 0.314f, 0.198f, 1.0f, 0.235f, 0.0f, 0.311f, 0.206f, 1.0f,
+ 0.233f, 0.0f, 0.309f, 0.214f, 1.0f, 0.231f, 0.0f, 0.306f, 0.223f, 1.0f, 0.23f, 0.0f, 0.304f, 0.231f, 1.0f, 0.228f, 0.0f, 0.301f, 0.24f, 1.0f,
+ 0.226f, 0.0f, 0.299f, 0.248f, 1.0f, 0.224f, 0.0f, 0.296f, 0.256f, 1.0f, 0.223f, 0.0f, 0.294f, 0.264f, 1.0f, 0.221f, 0.0f, 0.291f, 0.272f, 1.0f,
+ 0.219f, 0.0f, 0.288f, 0.28f, 1.0f, 0.218f, 0.0f, 0.286f, 0.287f, 1.0f, 0.216f, 0.0f, 0.283f, 0.294f, 1.0f, 0.214f, 0.0f, 0.281f, 0.301f, 1.0f,
+ 0.213f, 0.0f, 0.278f, 0.307f, 1.0f, 0.211f, 0.0f, 0.275f, 0.314f, 1.0f, 0.21f, 0.0f, 0.273f, 0.32f, 1.0f, 0.208f, 0.0f, 0.27f, 0.327f, 1.0f,
+ 0.206f, 0.0f, 0.267f, 0.333f, 1.0f, 0.205f, 0.0f, 0.265f, 0.339f, 1.0f, 0.204f, 0.0f, 0.262f, 0.345f, 1.0f, 0.202f, 0.0f, 0.259f, 0.351f, 1.0f,
+ 0.201f, 0.0f, 0.256f, 0.357f, 1.0f, 0.199f, 0.0f, 0.253f, 0.362f, 1.0f, 0.198f, 0.0f, 0.25f, 0.368f, 1.0f, 0.197f, 0.0f, 0.247f, 0.373f, 1.0f,
+ 0.195f, 0.0f, 0.244f, 0.379f, 1.0f, 0.194f, 0.0f, 0.241f, 0.383f, 1.0f, 0.193f, 0.0f, 0.238f, 0.388f, 1.0f, 0.192f, 0.0f, 0.235f, 0.392f, 1.0f,
+ 0.191f, 0.0f, 0.232f, 0.396f, 1.0f, 0.19f, 0.0f, 0.229f, 0.399f, 1.0f, 0.189f, 0.0f, 0.226f, 0.402f, 1.0f, 0.188f, 0.0f, 0.222f, 0.405f, 1.0f,
+ 0.187f, 0.0f, 0.219f, 0.407f, 1.0f, 0.186f, 0.0f, 0.216f, 0.409f, 1.0f, 0.185f, 0.0f, 0.213f, 0.411f, 1.0f, 0.184f, 0.0f, 0.209f, 0.412f, 1.0f,
+ 0.183f, 0.0f, 0.206f, 0.413f, 1.0f, 0.183f, 0.0f, 0.203f, 0.414f, 1.0f, 0.182f, 0.0f, 0.199f, 0.415f, 1.0f, 0.181f, 0.0f, 0.196f, 0.416f, 1.0f,
+ 0.181f, 0.0f, 0.193f, 0.417f, 1.0f, 0.18f, 0.0f, 0.189f, 0.417f, 1.0f, 0.18f, 0.0f, 0.186f, 0.418f, 1.0f, 0.179f, 0.0f, 0.182f, 0.419f, 1.0f,
+ 0.179f, 0.0f, 0.179f, 0.421f, 1.0f, 0.179f, 0.0f, 0.176f, 0.422f, 1.0f, 0.178f, 0.0f, 0.172f, 0.423f, 1.0f, 0.178f, 0.0f, 0.169f, 0.425f, 1.0f,
+ 0.178f, 0.0f, 0.165f, 0.427f, 1.0f, 0.178f, 0.0f, 0.162f, 0.429f, 1.0f, 0.178f, 0.0f, 0.158f, 0.431f, 1.0f, 0.178f, 0.0f, 0.155f, 0.434f, 1.0f,
+ 0.178f, 0.0f, 0.152f, 0.436f, 1.0f, 0.178f, 0.0f, 0.148f, 0.439f, 1.0f, 0.178f, 0.0f, 0.145f, 0.442f, 1.0f, 0.178f, 0.0f, 0.141f, 0.446f, 1.0f,
+ 0.178f, 0.0f, 0.138f, 0.449f, 1.0f, 0.178f, 0.0f, 0.134f, 0.453f, 1.0f, 0.178f, 0.0f, 0.131f, 0.458f, 1.0f, 0.179f, 0.0f, 0.127f, 0.462f, 1.0f,
+ 0.179f, 0.0f, 0.124f, 0.467f, 1.0f, 0.179f, 0.0f, 0.12f, 0.472f, 1.0f, 0.18f, 0.0f, 0.117f, 0.478f, 1.0f, 0.18f, 0.0f, 0.113f, 0.483f, 1.0f,
+ 0.181f, 0.0f, 0.11f, 0.489f, 1.0f, 0.182f, 0.0f, 0.106f, 0.494f, 1.0f, 0.182f, 0.0f, 0.103f, 0.5f, 1.0f, 0.183f, 0.0f, 0.099f, 0.505f, 1.0f,
+ 0.184f, 0.0f, 0.096f, 0.511f, 1.0f, 0.185f, 0.0f, 0.092f, 0.516f, 1.0f, 0.185f, 0.0f, 0.089f, 0.521f, 1.0f, 0.186f, 0.0f, 0.086f, 0.525f, 1.0f,
+ 0.187f, 0.0f, 0.082f, 0.53f, 1.0f, 0.188f, 0.0f, 0.079f, 0.534f, 1.0f, 0.189f, 0.0f, 0.076f, 0.537f, 1.0f, 0.191f, 0.0f, 0.073f, 0.541f, 1.0f,
+ 0.192f, 0.0f, 0.069f, 0.544f, 1.0f, 0.193f, 0.0f, 0.066f, 0.547f, 1.0f, 0.194f, 0.0f, 0.063f, 0.55f, 1.0f, 0.196f, 0.0f, 0.061f, 0.553f, 1.0f,
+ 0.197f, 0.0f, 0.058f, 0.556f, 1.0f, 0.198f, 0.0f, 0.055f, 0.559f, 1.0f, 0.2f, 0.0f, 0.052f, 0.562f, 1.0f, 0.201f, 0.0f, 0.049f, 0.564f, 1.0f,
+ 0.203f, 0.0f, 0.047f, 0.566f, 1.0f, 0.205f, 0.0f, 0.044f, 0.569f, 1.0f, 0.206f, 0.0f, 0.042f, 0.571f, 1.0f, 0.208f, 0.0f, 0.039f, 0.573f, 1.0f,
+ 0.21f, 0.0f, 0.037f, 0.575f, 1.0f, 0.212f, 0.0f, 0.035f, 0.576f, 1.0f, 0.214f, 0.0f, 0.032f, 0.578f, 1.0f, 0.215f, 0.0f, 0.03f, 0.579f, 1.0f,
+ 0.217f, 0.0f, 0.028f, 0.581f, 1.0f, 0.22f, 0.0f, 0.025f, 0.582f, 1.0f, 0.222f, 0.0f, 0.023f, 0.583f, 1.0f, 0.224f, 0.0f, 0.021f, 0.585f, 1.0f,
+ 0.226f, 0.0f, 0.019f, 0.587f, 1.0f, 0.228f, 0.0f, 0.016f, 0.589f, 1.0f, 0.231f, 0.0f, 0.014f, 0.592f, 1.0f, 0.233f, 0.0f, 0.012f, 0.596f, 1.0f,
+ 0.236f, 0.0f, 0.01f, 0.599f, 1.0f, 0.238f, 0.0f, 0.008f, 0.604f, 1.0f, 0.241f, 0.0f, 0.006f, 0.608f, 1.0f, 0.243f, 0.0f, 0.004f, 0.612f, 1.0f,
+ 0.246f, 0.0f, 0.002f, 0.615f, 1.0f, 0.249f, 0.0f, 0.0f, 0.619f, 1.0f, 0.251f, 0.0f, -0.002f, 0.622f, 1.0f, 0.254f, 0.0f, -0.003f, 0.624f, 1.0f,
+ 0.257f, 0.0f, -0.005f, 0.626f, 1.0f, 0.26f, 0.0f, -0.007f, 0.628f, 1.0f, 0.263f, 0.0f, -0.008f, 0.63f, 1.0f, 0.266f, 0.0f, -0.01f, 0.632f, 1.0f,
+ 0.269f, 0.0f, -0.011f, 0.634f, 1.0f, 0.272f, 0.0f, -0.013f, 0.636f, 1.0f, 0.275f, 0.0f, -0.014f, 0.638f, 1.0f, 0.278f, 0.0f, -0.015f, 0.64f, 1.0f,
+ 0.281f, 0.0f, -0.017f, 0.642f, 1.0f, 0.284f, 0.0f, -0.018f, 0.644f, 1.0f, 0.288f, 0.0f, -0.019f, 0.647f, 1.0f, 0.291f, 0.0f, -0.02f, 0.649f, 1.0f,
+ 0.294f, 0.0f, -0.021f, 0.651f, 1.0f, 0.297f, 0.0f, -0.022f, 0.653f, 1.0f, 0.301f, 0.0f, -0.023f, 0.656f, 1.0f, 0.304f, 0.0f, -0.024f, 0.658f, 1.0f,
+ 0.307f, 0.0f, -0.025f, 0.659f, 1.0f, 0.31f, 0.0f, -0.026f, 0.661f, 1.0f, 0.314f, 0.0f, -0.027f, 0.662f, 1.0f, 0.317f, 0.0f, -0.027f, 0.664f, 1.0f,
+ 0.32f, 0.0f, -0.028f, 0.665f, 1.0f, 0.324f, 0.0f, -0.028f, 0.665f, 1.0f, 0.327f, 0.0f, -0.029f, 0.666f, 1.0f, 0.33f, 0.0f, -0.029f, 0.666f, 1.0f,
+ 0.334f, 0.0f, -0.029f, 0.667f, 1.0f, 0.337f, 0.0f, -0.03f, 0.667f, 1.0f, 0.341f, 0.0f, -0.03f, 0.668f, 1.0f, 0.344f, 0.0f, -0.03f, 0.668f, 1.0f,
+ 0.348f, 0.0f, -0.03f, 0.668f, 1.0f, 0.351f, 0.0f, -0.03f, 0.668f, 1.0f, 0.354f, 0.0f, -0.03f, 0.668f, 1.0f, 0.358f, 0.0f, -0.029f, 0.668f, 1.0f,
+ 0.361f, 0.0f, -0.029f, 0.668f, 1.0f, 0.365f, 0.0f, -0.029f, 0.668f, 1.0f, 0.368f, 0.0f, -0.028f, 0.668f, 1.0f, 0.372f, 0.0f, -0.028f, 0.668f, 1.0f,
+ 0.375f, 0.0f, -0.027f, 0.668f, 1.0f, 0.378f, 0.0f, -0.027f, 0.668f, 1.0f, 0.382f, 0.0f, -0.026f, 0.667f, 1.0f, 0.385f, 0.0f, -0.025f, 0.667f, 1.0f,
+ 0.388f, 0.0f, -0.025f, 0.666f, 1.0f, 0.392f, 0.0f, -0.024f, 0.666f, 1.0f, 0.395f, 0.0f, -0.023f, 0.665f, 1.0f, 0.398f, 0.0f, -0.022f, 0.664f, 1.0f,
+ 0.401f, 0.0f, -0.021f, 0.664f, 1.0f, 0.405f, 0.0f, -0.02f, 0.663f, 1.0f, 0.408f, 0.0f, -0.019f, 0.663f, 1.0f, 0.411f, 0.0f, -0.018f, 0.662f, 1.0f,
+ 0.414f, 0.0f, -0.017f, 0.662f, 1.0f, 0.417f, 0.0f, -0.016f, 0.662f, 1.0f, 0.42f, 0.0f, -0.015f, 0.662f, 1.0f, 0.423f, 0.0f, -0.014f, 0.661f, 1.0f,
+ 0.426f, 0.0f, -0.012f, 0.661f, 1.0f, 0.429f, 0.0f, -0.011f, 0.661f, 1.0f, 0.432f, 0.0f, -0.01f, 0.661f, 1.0f, 0.434f, 0.0f, -0.009f, 0.66f, 1.0f,
+ 0.437f, 0.0f, -0.007f, 0.66f, 1.0f, 0.44f, 0.0f, -0.006f, 0.659f, 1.0f, 0.442f, 0.0f, -0.005f, 0.659f, 1.0f, 0.445f, 0.0f, -0.003f, 0.658f, 1.0f,
+ 0.448f, 0.0f, -0.002f, 0.658f, 1.0f, 0.45f, 0.0f, -0.001f, 0.657f, 1.0f, 0.452f, 0.0f, 0.001f, 0.656f, 1.0f, 0.455f, 0.0f, 0.002f, 0.655f, 1.0f,
+ 0.457f, 0.0f, 0.004f, 0.654f, 1.0f, 0.459f, 0.0f, 0.005f, 0.653f, 1.0f, 0.462f, 0.0f, 0.007f, 0.652f, 1.0f, 0.464f, 0.0f, 0.009f, 0.651f, 1.0f,
+ 0.466f, 0.0f, 0.01f, 0.65f, 1.0f, 0.468f, 0.0f, 0.012f, 0.65f, 1.0f, 0.47f, 0.0f, 0.014f, 0.649f, 1.0f, 0.472f, 0.0f, 0.016f, 0.648f, 1.0f,
+ 0.474f, 0.0f, 0.018f, 0.647f, 1.0f, 0.476f, 0.0f, 0.019f, 0.646f, 1.0f, 0.478f, 0.0f, 0.021f, 0.645f, 1.0f, 0.479f, 0.0f, 0.023f, 0.644f, 1.0f,
+ 0.481f, 0.0f, 0.025f, 0.643f, 1.0f, 0.483f, 0.0f, 0.027f, 0.642f, 1.0f, 0.485f, 0.0f, 0.03f, 0.642f, 1.0f, 0.486f, 0.0f, 0.032f, 0.641f, 1.0f,
+ 0.488f, 0.0f, 0.034f, 0.64f, 1.0f, 0.49f, 0.0f, 0.036f, 0.639f, 1.0f, 0.491f, 0.0f, 0.038f, 0.638f, 1.0f, 0.493f, 0.0f, 0.041f, 0.637f, 1.0f,
+ 0.494f, 0.0f, 0.043f, 0.636f, 1.0f, 0.496f, 0.0f, 0.045f, 0.635f, 1.0f, 0.497f, 0.0f, 0.048f, 0.635f, 1.0f, 0.499f, 0.0f, 0.05f, 0.634f, 1.0f,
+ 0.5f, 0.0f, 0.053f, 0.633f, 1.0f, 0.502f, 0.0f, 0.055f, 0.632f, 1.0f, 0.503f, 0.0f, 0.058f, 0.631f, 1.0f, 0.505f, 0.0f, 0.06f, 0.63f, 1.0f,
+ 0.506f, 0.0f, 0.063f, 0.63f, 1.0f, 0.507f, 0.0f, 0.066f, 0.629f, 1.0f, 0.509f, 0.0f, 0.068f, 0.628f, 1.0f, 0.51f, 0.0f, 0.071f, 0.628f, 1.0f,
+ 0.511f, 0.0f, 0.074f, 0.627f, 1.0f, 0.513f, 0.0f, 0.077f, 0.626f, 1.0f, 0.514f, 0.0f, 0.079f, 0.625f, 1.0f, 0.515f, 0.0f, 0.082f, 0.625f, 1.0f,
+ 0.516f, 0.0f, 0.085f, 0.624f, 1.0f, 0.518f, 0.0f, 0.088f, 0.623f, 1.0f, 0.519f, 0.0f, 0.091f, 0.622f, 1.0f, 0.52f, 0.0f, 0.094f, 0.62f, 1.0f,
+ 0.521f, 0.0f, 0.098f, 0.619f, 1.0f, 0.522f, 0.0f, 0.101f, 0.617f, 1.0f, 0.523f, 0.0f, 0.104f, 0.615f, 1.0f, 0.524f, 0.0f, 0.107f, 0.613f, 1.0f,
+ 0.525f, 0.0f, 0.111f, 0.611f, 1.0f, 0.526f, 0.0f, 0.114f, 0.609f, 1.0f, 0.527f, 0.0f, 0.118f, 0.607f, 1.0f, 0.527f, 0.0f, 0.121f, 0.605f, 1.0f,
+ 0.528f, 0.0f, 0.124f, 0.603f, 1.0f, 0.529f, 0.0f, 0.128f, 0.602f, 1.0f, 0.529f, 0.0f, 0.132f, 0.6f, 1.0f, 0.53f, 0.0f, 0.135f, 0.599f, 1.0f,
+ 0.531f, 0.0f, 0.139f, 0.598f, 1.0f, 0.531f, 0.0f, 0.142f, 0.598f, 1.0f, 0.531f, 0.0f, 0.146f, 0.597f, 1.0f, 0.532f, 0.0f, 0.15f, 0.596f, 1.0f,
+ 0.532f, 0.0f, 0.154f, 0.596f, 1.0f, 0.532f, 0.0f, 0.157f, 0.595f, 1.0f, 0.532f, 0.0f, 0.161f, 0.595f, 1.0f, 0.532f, 0.0f, 0.165f, 0.594f, 1.0f,
+ 0.532f, 0.0f, 0.169f, 0.593f, 1.0f, 0.532f, 0.0f, 0.173f, 0.592f, 1.0f, 0.532f, 0.0f, 0.177f, 0.591f, 1.0f, 0.532f, 0.0f, 0.181f, 0.59f, 1.0f,
+ 0.531f, 0.0f, 0.185f, 0.589f, 1.0f, 0.531f, 0.0f, 0.189f, 0.588f, 1.0f, 0.53f, 0.0f, 0.194f, 0.587f, 1.0f, 0.529f, 0.0f, 0.198f, 0.586f, 1.0f,
+ 0.528f, 0.0f, 0.202f, 0.585f, 1.0f, 0.527f, 0.0f, 0.207f, 0.584f, 1.0f, 0.526f, 0.0f, 0.211f, 0.584f, 1.0f, 0.525f, 0.0f, 0.215f, 0.583f, 1.0f,
+ 0.523f, 0.0f, 0.22f, 0.583f, 1.0f, 0.522f, 0.0f, 0.224f, 0.583f, 1.0f, 0.52f, 0.0f, 0.229f, 0.582f, 1.0f, 0.518f, 0.0f, 0.234f, 0.582f, 1.0f,
+ 0.515f, 0.0f, 0.238f, 0.582f, 1.0f, 0.513f, 0.0f, 0.243f, 0.581f, 1.0f, 0.51f, 0.0f, 0.247f, 0.58f, 1.0f, 0.508f, 0.0f, 0.252f, 0.579f, 1.0f,
+ 0.505f, 0.0f, 0.257f, 0.578f, 1.0f, 0.502f, 0.0f, 0.261f, 0.576f, 1.0f, 0.499f, 0.0f, 0.266f, 0.573f, 1.0f, 0.496f, 0.0f, 0.27f, 0.57f, 1.0f,
+ 0.492f, 0.0f, 0.275f, 0.566f, 1.0f, 0.489f, 0.0f, 0.279f, 0.561f, 1.0f, 0.485f, 0.0f, 0.284f, 0.555f, 1.0f, 0.481f, 0.0f, 0.288f, 0.548f, 1.0f,
+ 0.478f, 0.0f, 0.293f, 0.54f, 1.0f, 0.473f, 0.0f, 0.297f, 0.531f, 1.0f, 0.469f, 0.0f, 0.301f, 0.521f, 1.0f, 0.465f, 0.0f, 0.305f, 0.509f, 1.0f,
+ 0.461f, 0.0f, 0.309f, 0.496f, 1.0f, 0.456f, 0.0f, 0.313f, 0.481f, 1.0f, 0.452f, 0.0f, 0.317f, 0.464f, 1.0f, 0.448f, 0.0f, 0.321f, 0.445f, 1.0f,
+ 0.443f, 0.0f, 0.324f, 0.424f, 1.0f, 0.438f, 0.0f, 0.328f, 0.401f, 1.0f, 0.434f, 0.0f, 0.331f, 0.374f, 1.0f, 0.429f, 0.0f, 0.334f, 0.346f, 1.0f,
+ 0.425f, 0.0f, 0.337f, 0.314f, 1.0f, 0.421f, 0.0f, 0.34f, 0.281f, 1.0f, 0.416f, 0.0f, 0.343f, 0.245f, 1.0f, 0.412f, 0.0f, 0.346f, 0.208f, 1.0f,
+ 0.408f, 0.0f, 0.349f, 0.169f, 1.0f, 0.404f, 0.0f, 0.351f, 0.13f, 1.0f, 0.401f, 0.0f, 0.354f, 0.089f, 1.0f, 0.398f, 0.0f, 0.356f, 0.054f, 1.0f,
+ 0.394f, 0.0f, 0.359f, 0.0f, 1.0f,
+};
+
+static const float data23[209 * GP_PRIM_DATABUF_SIZE] = {
+ -0.751f, 0.0f, 0.173f, 0.0f, 1.0f, -0.751f, 0.0f, 0.168f, 0.0f, 1.0f, -0.75f, 0.0f, 0.164f, 0.0f, 1.0f, -0.75f, 0.0f, 0.16f, 0.0f, 1.0f,
+ -0.75f, 0.0f, 0.156f, 0.0f, 1.0f, -0.749f, 0.0f, 0.152f, 0.0f, 1.0f, -0.749f, 0.0f, 0.148f, 0.0f, 1.0f, -0.748f, 0.0f, 0.144f, 0.0f, 1.0f,
+ -0.747f, 0.0f, 0.14f, 0.001f, 1.0f, -0.747f, 0.0f, 0.137f, 0.002f, 1.0f, -0.746f, 0.0f, 0.133f, 0.005f, 1.0f, -0.745f, 0.0f, 0.129f, 0.008f, 1.0f,
+ -0.745f, 0.0f, 0.125f, 0.013f, 1.0f, -0.744f, 0.0f, 0.122f, 0.02f, 1.0f, -0.743f, 0.0f, 0.118f, 0.028f, 1.0f, -0.742f, 0.0f, 0.115f, 0.038f, 1.0f,
+ -0.741f, 0.0f, 0.111f, 0.049f, 1.0f, -0.74f, 0.0f, 0.108f, 0.061f, 1.0f, -0.739f, 0.0f, 0.105f, 0.073f, 1.0f, -0.738f, 0.0f, 0.101f, 0.085f, 1.0f,
+ -0.736f, 0.0f, 0.098f, 0.097f, 1.0f, -0.735f, 0.0f, 0.095f, 0.109f, 1.0f, -0.734f, 0.0f, 0.091f, 0.119f, 1.0f, -0.732f, 0.0f, 0.088f, 0.129f, 1.0f,
+ -0.731f, 0.0f, 0.085f, 0.138f, 1.0f, -0.729f, 0.0f, 0.082f, 0.146f, 1.0f, -0.728f, 0.0f, 0.079f, 0.153f, 1.0f, -0.726f, 0.0f, 0.076f, 0.158f, 1.0f,
+ -0.725f, 0.0f, 0.073f, 0.163f, 1.0f, -0.723f, 0.0f, 0.07f, 0.167f, 1.0f, -0.722f, 0.0f, 0.067f, 0.17f, 1.0f, -0.72f, 0.0f, 0.065f, 0.173f, 1.0f,
+ -0.718f, 0.0f, 0.062f, 0.174f, 1.0f, -0.717f, 0.0f, 0.059f, 0.175f, 1.0f, -0.715f, 0.0f, 0.057f, 0.176f, 1.0f, -0.714f, 0.0f, 0.054f, 0.176f, 1.0f,
+ -0.712f, 0.0f, 0.051f, 0.176f, 1.0f, -0.71f, 0.0f, 0.049f, 0.176f, 1.0f, -0.709f, 0.0f, 0.046f, 0.176f, 1.0f, -0.707f, 0.0f, 0.043f, 0.176f, 1.0f,
+ -0.705f, 0.0f, 0.041f, 0.176f, 1.0f, -0.703f, 0.0f, 0.038f, 0.176f, 1.0f, -0.701f, 0.0f, 0.035f, 0.176f, 1.0f, -0.7f, 0.0f, 0.033f, 0.177f, 1.0f,
+ -0.698f, 0.0f, 0.03f, 0.177f, 1.0f, -0.696f, 0.0f, 0.027f, 0.178f, 1.0f, -0.694f, 0.0f, 0.024f, 0.179f, 1.0f, -0.692f, 0.0f, 0.022f, 0.18f, 1.0f,
+ -0.69f, 0.0f, 0.019f, 0.181f, 1.0f, -0.688f, 0.0f, 0.016f, 0.182f, 1.0f, -0.685f, 0.0f, 0.013f, 0.184f, 1.0f, -0.683f, 0.0f, 0.01f, 0.187f, 1.0f,
+ -0.681f, 0.0f, 0.007f, 0.19f, 1.0f, -0.679f, 0.0f, 0.004f, 0.194f, 1.0f, -0.677f, 0.0f, 0.001f, 0.198f, 1.0f, -0.675f, 0.0f, -0.002f, 0.203f, 1.0f,
+ -0.673f, 0.0f, -0.005f, 0.209f, 1.0f, -0.67f, 0.0f, -0.008f, 0.215f, 1.0f, -0.668f, 0.0f, -0.011f, 0.222f, 1.0f, -0.666f, 0.0f, -0.014f, 0.229f, 1.0f,
+ -0.664f, 0.0f, -0.017f, 0.237f, 1.0f, -0.661f, 0.0f, -0.02f, 0.246f, 1.0f, -0.659f, 0.0f, -0.023f, 0.255f, 1.0f, -0.657f, 0.0f, -0.025f, 0.264f, 1.0f,
+ -0.654f, 0.0f, -0.028f, 0.275f, 1.0f, -0.652f, 0.0f, -0.031f, 0.285f, 1.0f, -0.65f, 0.0f, -0.034f, 0.297f, 1.0f, -0.647f, 0.0f, -0.037f, 0.309f, 1.0f,
+ -0.644f, 0.0f, -0.04f, 0.322f, 1.0f, -0.642f, 0.0f, -0.043f, 0.335f, 1.0f, -0.639f, 0.0f, -0.046f, 0.348f, 1.0f, -0.636f, 0.0f, -0.049f, 0.361f, 1.0f,
+ -0.633f, 0.0f, -0.052f, 0.374f, 1.0f, -0.63f, 0.0f, -0.055f, 0.386f, 1.0f, -0.627f, 0.0f, -0.058f, 0.397f, 1.0f, -0.624f, 0.0f, -0.061f, 0.408f, 1.0f,
+ -0.62f, 0.0f, -0.064f, 0.418f, 1.0f, -0.617f, 0.0f, -0.067f, 0.427f, 1.0f, -0.614f, 0.0f, -0.07f, 0.435f, 1.0f, -0.611f, 0.0f, -0.073f, 0.443f, 1.0f,
+ -0.607f, 0.0f, -0.075f, 0.451f, 1.0f, -0.604f, 0.0f, -0.078f, 0.458f, 1.0f, -0.6f, 0.0f, -0.081f, 0.465f, 1.0f, -0.597f, 0.0f, -0.084f, 0.472f, 1.0f,
+ -0.593f, 0.0f, -0.086f, 0.479f, 1.0f, -0.59f, 0.0f, -0.089f, 0.486f, 1.0f, -0.586f, 0.0f, -0.092f, 0.492f, 1.0f, -0.583f, 0.0f, -0.094f, 0.499f, 1.0f,
+ -0.579f, 0.0f, -0.097f, 0.505f, 1.0f, -0.575f, 0.0f, -0.099f, 0.512f, 1.0f, -0.571f, 0.0f, -0.102f, 0.518f, 1.0f, -0.567f, 0.0f, -0.105f, 0.524f, 1.0f,
+ -0.563f, 0.0f, -0.107f, 0.53f, 1.0f, -0.559f, 0.0f, -0.11f, 0.536f, 1.0f, -0.555f, 0.0f, -0.112f, 0.541f, 1.0f, -0.551f, 0.0f, -0.115f, 0.546f, 1.0f,
+ -0.546f, 0.0f, -0.117f, 0.551f, 1.0f, -0.542f, 0.0f, -0.12f, 0.555f, 1.0f, -0.538f, 0.0f, -0.122f, 0.559f, 1.0f, -0.533f, 0.0f, -0.125f, 0.562f, 1.0f,
+ -0.529f, 0.0f, -0.127f, 0.565f, 1.0f, -0.525f, 0.0f, -0.129f, 0.568f, 1.0f, -0.52f, 0.0f, -0.132f, 0.57f, 1.0f, -0.516f, 0.0f, -0.134f, 0.572f, 1.0f,
+ -0.512f, 0.0f, -0.137f, 0.574f, 1.0f, -0.508f, 0.0f, -0.139f, 0.576f, 1.0f, -0.503f, 0.0f, -0.141f, 0.577f, 1.0f, -0.499f, 0.0f, -0.144f, 0.578f, 1.0f,
+ -0.495f, 0.0f, -0.146f, 0.579f, 1.0f, -0.491f, 0.0f, -0.148f, 0.579f, 1.0f, -0.487f, 0.0f, -0.151f, 0.578f, 1.0f, -0.483f, 0.0f, -0.153f, 0.577f, 1.0f,
+ -0.479f, 0.0f, -0.155f, 0.574f, 1.0f, -0.475f, 0.0f, -0.158f, 0.571f, 1.0f, -0.471f, 0.0f, -0.16f, 0.567f, 1.0f, -0.467f, 0.0f, -0.162f, 0.561f, 1.0f,
+ -0.463f, 0.0f, -0.165f, 0.555f, 1.0f, -0.459f, 0.0f, -0.167f, 0.548f, 1.0f, -0.456f, 0.0f, -0.169f, 0.54f, 1.0f, -0.452f, 0.0f, -0.172f, 0.532f, 1.0f,
+ -0.448f, 0.0f, -0.174f, 0.523f, 1.0f, -0.445f, 0.0f, -0.176f, 0.514f, 1.0f, -0.441f, 0.0f, -0.179f, 0.505f, 1.0f, -0.438f, 0.0f, -0.181f, 0.497f, 1.0f,
+ -0.435f, 0.0f, -0.183f, 0.488f, 1.0f, -0.431f, 0.0f, -0.185f, 0.48f, 1.0f, -0.428f, 0.0f, -0.188f, 0.472f, 1.0f, -0.425f, 0.0f, -0.19f, 0.464f, 1.0f,
+ -0.422f, 0.0f, -0.192f, 0.457f, 1.0f, -0.419f, 0.0f, -0.194f, 0.451f, 1.0f, -0.416f, 0.0f, -0.196f, 0.444f, 1.0f, -0.413f, 0.0f, -0.198f, 0.439f, 1.0f,
+ -0.41f, 0.0f, -0.2f, 0.434f, 1.0f, -0.407f, 0.0f, -0.202f, 0.429f, 1.0f, -0.404f, 0.0f, -0.204f, 0.426f, 1.0f, -0.401f, 0.0f, -0.206f, 0.422f, 1.0f,
+ -0.398f, 0.0f, -0.208f, 0.419f, 1.0f, -0.396f, 0.0f, -0.21f, 0.417f, 1.0f, -0.393f, 0.0f, -0.212f, 0.415f, 1.0f, -0.39f, 0.0f, -0.213f, 0.413f, 1.0f,
+ -0.388f, 0.0f, -0.215f, 0.412f, 1.0f, -0.385f, 0.0f, -0.217f, 0.411f, 1.0f, -0.382f, 0.0f, -0.219f, 0.41f, 1.0f, -0.38f, 0.0f, -0.221f, 0.41f, 1.0f,
+ -0.377f, 0.0f, -0.222f, 0.409f, 1.0f, -0.375f, 0.0f, -0.224f, 0.409f, 1.0f, -0.372f, 0.0f, -0.226f, 0.409f, 1.0f, -0.37f, 0.0f, -0.228f, 0.409f, 1.0f,
+ -0.367f, 0.0f, -0.229f, 0.409f, 1.0f, -0.365f, 0.0f, -0.231f, 0.409f, 1.0f, -0.362f, 0.0f, -0.233f, 0.409f, 1.0f, -0.36f, 0.0f, -0.235f, 0.409f, 1.0f,
+ -0.357f, 0.0f, -0.236f, 0.409f, 1.0f, -0.355f, 0.0f, -0.238f, 0.409f, 1.0f, -0.352f, 0.0f, -0.24f, 0.408f, 1.0f, -0.35f, 0.0f, -0.242f, 0.408f, 1.0f,
+ -0.348f, 0.0f, -0.243f, 0.407f, 1.0f, -0.345f, 0.0f, -0.245f, 0.406f, 1.0f, -0.343f, 0.0f, -0.247f, 0.405f, 1.0f, -0.34f, 0.0f, -0.249f, 0.404f, 1.0f,
+ -0.338f, 0.0f, -0.251f, 0.403f, 1.0f, -0.336f, 0.0f, -0.253f, 0.401f, 1.0f, -0.333f, 0.0f, -0.255f, 0.399f, 1.0f, -0.331f, 0.0f, -0.256f, 0.397f, 1.0f,
+ -0.329f, 0.0f, -0.258f, 0.394f, 1.0f, -0.327f, 0.0f, -0.26f, 0.391f, 1.0f, -0.324f, 0.0f, -0.262f, 0.387f, 1.0f, -0.322f, 0.0f, -0.264f, 0.383f, 1.0f,
+ -0.32f, 0.0f, -0.266f, 0.379f, 1.0f, -0.318f, 0.0f, -0.268f, 0.374f, 1.0f, -0.316f, 0.0f, -0.27f, 0.368f, 1.0f, -0.314f, 0.0f, -0.272f, 0.362f, 1.0f,
+ -0.312f, 0.0f, -0.275f, 0.356f, 1.0f, -0.309f, 0.0f, -0.277f, 0.349f, 1.0f, -0.307f, 0.0f, -0.279f, 0.341f, 1.0f, -0.305f, 0.0f, -0.281f, 0.333f, 1.0f,
+ -0.303f, 0.0f, -0.283f, 0.325f, 1.0f, -0.301f, 0.0f, -0.286f, 0.316f, 1.0f, -0.299f, 0.0f, -0.288f, 0.307f, 1.0f, -0.297f, 0.0f, -0.29f, 0.298f, 1.0f,
+ -0.295f, 0.0f, -0.293f, 0.289f, 1.0f, -0.293f, 0.0f, -0.295f, 0.279f, 1.0f, -0.291f, 0.0f, -0.298f, 0.269f, 1.0f, -0.29f, 0.0f, -0.3f, 0.259f, 1.0f,
+ -0.288f, 0.0f, -0.303f, 0.249f, 1.0f, -0.286f, 0.0f, -0.306f, 0.238f, 1.0f, -0.284f, 0.0f, -0.308f, 0.227f, 1.0f, -0.282f, 0.0f, -0.311f, 0.215f, 1.0f,
+ -0.28f, 0.0f, -0.314f, 0.203f, 1.0f, -0.278f, 0.0f, -0.317f, 0.191f, 1.0f, -0.277f, 0.0f, -0.32f, 0.178f, 1.0f, -0.275f, 0.0f, -0.323f, 0.165f, 1.0f,
+ -0.273f, 0.0f, -0.326f, 0.151f, 1.0f, -0.271f, 0.0f, -0.33f, 0.138f, 1.0f, -0.27f, 0.0f, -0.333f, 0.124f, 1.0f, -0.268f, 0.0f, -0.336f, 0.11f, 1.0f,
+ -0.267f, 0.0f, -0.34f, 0.097f, 1.0f, -0.265f, 0.0f, -0.343f, 0.085f, 1.0f, -0.264f, 0.0f, -0.346f, 0.073f, 1.0f, -0.262f, 0.0f, -0.35f, 0.062f, 1.0f,
+ -0.261f, 0.0f, -0.353f, 0.052f, 1.0f, -0.259f, 0.0f, -0.357f, 0.043f, 1.0f, -0.258f, 0.0f, -0.36f, 0.035f, 1.0f, -0.257f, 0.0f, -0.363f, 0.028f, 1.0f,
+ -0.255f, 0.0f, -0.366f, 0.021f, 1.0f, -0.254f, 0.0f, -0.369f, 0.016f, 1.0f, -0.253f, 0.0f, -0.372f, 0.01f, 1.0f, -0.252f, 0.0f, -0.375f, 0.006f, 1.0f,
+ -0.251f, 0.0f, -0.379f, 0.0f, 1.0f,
+};
+
+static const float data24[133 * GP_PRIM_DATABUF_SIZE] = {
+ 0.233f, 0.0f, -0.376f, 0.021f, 1.0f, 0.234f, 0.0f, -0.372f, 0.08f, 1.0f, 0.234f, 0.0f, -0.369f, 0.116f, 1.0f, 0.234f, 0.0f, -0.366f, 0.156f, 1.0f,
+ 0.235f, 0.0f, -0.362f, 0.191f, 1.0f, 0.236f, 0.0f, -0.359f, 0.222f, 1.0f, 0.236f, 0.0f, -0.356f, 0.248f, 1.0f, 0.237f, 0.0f, -0.353f, 0.27f, 1.0f,
+ 0.238f, 0.0f, -0.35f, 0.289f, 1.0f, 0.239f, 0.0f, -0.346f, 0.304f, 1.0f, 0.24f, 0.0f, -0.343f, 0.319f, 1.0f, 0.241f, 0.0f, -0.34f, 0.334f, 1.0f,
+ 0.242f, 0.0f, -0.337f, 0.35f, 1.0f, 0.243f, 0.0f, -0.335f, 0.367f, 1.0f, 0.244f, 0.0f, -0.332f, 0.385f, 1.0f, 0.245f, 0.0f, -0.329f, 0.401f, 1.0f,
+ 0.247f, 0.0f, -0.327f, 0.415f, 1.0f, 0.248f, 0.0f, -0.324f, 0.426f, 1.0f, 0.249f, 0.0f, -0.322f, 0.435f, 1.0f, 0.251f, 0.0f, -0.32f, 0.443f, 1.0f,
+ 0.252f, 0.0f, -0.318f, 0.449f, 1.0f, 0.254f, 0.0f, -0.316f, 0.455f, 1.0f, 0.255f, 0.0f, -0.314f, 0.461f, 1.0f, 0.257f, 0.0f, -0.312f, 0.467f, 1.0f,
+ 0.258f, 0.0f, -0.311f, 0.474f, 1.0f, 0.26f, 0.0f, -0.309f, 0.48f, 1.0f, 0.262f, 0.0f, -0.307f, 0.487f, 1.0f, 0.263f, 0.0f, -0.305f, 0.493f, 1.0f,
+ 0.265f, 0.0f, -0.303f, 0.499f, 1.0f, 0.267f, 0.0f, -0.3f, 0.505f, 1.0f, 0.269f, 0.0f, -0.298f, 0.511f, 1.0f, 0.271f, 0.0f, -0.296f, 0.518f, 1.0f,
+ 0.273f, 0.0f, -0.294f, 0.524f, 1.0f, 0.276f, 0.0f, -0.291f, 0.531f, 1.0f, 0.278f, 0.0f, -0.289f, 0.539f, 1.0f, 0.281f, 0.0f, -0.287f, 0.546f, 1.0f,
+ 0.283f, 0.0f, -0.284f, 0.552f, 1.0f, 0.286f, 0.0f, -0.281f, 0.557f, 1.0f, 0.289f, 0.0f, -0.279f, 0.561f, 1.0f, 0.292f, 0.0f, -0.276f, 0.565f, 1.0f,
+ 0.294f, 0.0f, -0.274f, 0.568f, 1.0f, 0.297f, 0.0f, -0.271f, 0.57f, 1.0f, 0.3f, 0.0f, -0.269f, 0.572f, 1.0f, 0.303f, 0.0f, -0.267f, 0.574f, 1.0f,
+ 0.306f, 0.0f, -0.264f, 0.575f, 1.0f, 0.308f, 0.0f, -0.262f, 0.576f, 1.0f, 0.311f, 0.0f, -0.26f, 0.577f, 1.0f, 0.314f, 0.0f, -0.257f, 0.578f, 1.0f,
+ 0.316f, 0.0f, -0.255f, 0.578f, 1.0f, 0.319f, 0.0f, -0.253f, 0.579f, 1.0f, 0.322f, 0.0f, -0.25f, 0.579f, 1.0f, 0.325f, 0.0f, -0.248f, 0.58f, 1.0f,
+ 0.328f, 0.0f, -0.246f, 0.58f, 1.0f, 0.331f, 0.0f, -0.243f, 0.58f, 1.0f, 0.334f, 0.0f, -0.241f, 0.58f, 1.0f, 0.337f, 0.0f, -0.239f, 0.58f, 1.0f,
+ 0.341f, 0.0f, -0.236f, 0.58f, 1.0f, 0.344f, 0.0f, -0.233f, 0.581f, 1.0f, 0.348f, 0.0f, -0.231f, 0.581f, 1.0f, 0.352f, 0.0f, -0.228f, 0.581f, 1.0f,
+ 0.356f, 0.0f, -0.225f, 0.582f, 1.0f, 0.36f, 0.0f, -0.222f, 0.582f, 1.0f, 0.365f, 0.0f, -0.219f, 0.582f, 1.0f, 0.369f, 0.0f, -0.216f, 0.582f, 1.0f,
+ 0.374f, 0.0f, -0.214f, 0.582f, 1.0f, 0.378f, 0.0f, -0.211f, 0.582f, 1.0f, 0.383f, 0.0f, -0.208f, 0.583f, 1.0f, 0.387f, 0.0f, -0.205f, 0.583f, 1.0f,
+ 0.392f, 0.0f, -0.202f, 0.583f, 1.0f, 0.397f, 0.0f, -0.199f, 0.583f, 1.0f, 0.401f, 0.0f, -0.197f, 0.583f, 1.0f, 0.406f, 0.0f, -0.194f, 0.583f, 1.0f,
+ 0.411f, 0.0f, -0.191f, 0.583f, 1.0f, 0.416f, 0.0f, -0.188f, 0.583f, 1.0f, 0.42f, 0.0f, -0.186f, 0.583f, 1.0f, 0.425f, 0.0f, -0.183f, 0.583f, 1.0f,
+ 0.43f, 0.0f, -0.18f, 0.583f, 1.0f, 0.434f, 0.0f, -0.178f, 0.583f, 1.0f, 0.439f, 0.0f, -0.175f, 0.583f, 1.0f, 0.444f, 0.0f, -0.172f, 0.583f, 1.0f,
+ 0.449f, 0.0f, -0.17f, 0.584f, 1.0f, 0.453f, 0.0f, -0.167f, 0.584f, 1.0f, 0.458f, 0.0f, -0.164f, 0.584f, 1.0f, 0.463f, 0.0f, -0.161f, 0.585f, 1.0f,
+ 0.468f, 0.0f, -0.158f, 0.585f, 1.0f, 0.473f, 0.0f, -0.155f, 0.585f, 1.0f, 0.478f, 0.0f, -0.152f, 0.585f, 1.0f, 0.483f, 0.0f, -0.149f, 0.585f, 1.0f,
+ 0.488f, 0.0f, -0.146f, 0.585f, 1.0f, 0.492f, 0.0f, -0.143f, 0.585f, 1.0f, 0.497f, 0.0f, -0.14f, 0.586f, 1.0f, 0.501f, 0.0f, -0.137f, 0.586f, 1.0f,
+ 0.506f, 0.0f, -0.134f, 0.586f, 1.0f, 0.51f, 0.0f, -0.13f, 0.586f, 1.0f, 0.515f, 0.0f, -0.127f, 0.586f, 1.0f, 0.52f, 0.0f, -0.124f, 0.586f, 1.0f,
+ 0.524f, 0.0f, -0.12f, 0.586f, 1.0f, 0.529f, 0.0f, -0.117f, 0.586f, 1.0f, 0.534f, 0.0f, -0.113f, 0.586f, 1.0f, 0.539f, 0.0f, -0.109f, 0.586f, 1.0f,
+ 0.544f, 0.0f, -0.105f, 0.586f, 1.0f, 0.55f, 0.0f, -0.1f, 0.586f, 1.0f, 0.555f, 0.0f, -0.095f, 0.586f, 1.0f, 0.561f, 0.0f, -0.09f, 0.586f, 1.0f,
+ 0.567f, 0.0f, -0.084f, 0.587f, 1.0f, 0.573f, 0.0f, -0.078f, 0.587f, 1.0f, 0.579f, 0.0f, -0.071f, 0.587f, 1.0f, 0.586f, 0.0f, -0.063f, 0.588f, 1.0f,
+ 0.593f, 0.0f, -0.055f, 0.588f, 1.0f, 0.6f, 0.0f, -0.047f, 0.588f, 1.0f, 0.607f, 0.0f, -0.038f, 0.589f, 1.0f, 0.614f, 0.0f, -0.028f, 0.589f, 1.0f,
+ 0.621f, 0.0f, -0.018f, 0.589f, 1.0f, 0.629f, 0.0f, -0.007f, 0.589f, 1.0f, 0.636f, 0.0f, 0.004f, 0.589f, 1.0f, 0.643f, 0.0f, 0.015f, 0.59f, 1.0f,
+ 0.65f, 0.0f, 0.026f, 0.589f, 1.0f, 0.656f, 0.0f, 0.038f, 0.589f, 1.0f, 0.663f, 0.0f, 0.049f, 0.588f, 1.0f, 0.669f, 0.0f, 0.06f, 0.587f, 1.0f,
+ 0.676f, 0.0f, 0.072f, 0.584f, 1.0f, 0.682f, 0.0f, 0.084f, 0.579f, 1.0f, 0.688f, 0.0f, 0.096f, 0.571f, 1.0f, 0.694f, 0.0f, 0.108f, 0.558f, 1.0f,
+ 0.7f, 0.0f, 0.12f, 0.54f, 1.0f, 0.706f, 0.0f, 0.133f, 0.514f, 1.0f, 0.712f, 0.0f, 0.145f, 0.478f, 1.0f, 0.718f, 0.0f, 0.158f, 0.431f, 1.0f,
+ 0.723f, 0.0f, 0.17f, 0.369f, 1.0f, 0.728f, 0.0f, 0.182f, 0.294f, 1.0f, 0.733f, 0.0f, 0.194f, 0.205f, 1.0f, 0.737f, 0.0f, 0.204f, 0.125f, 1.0f,
+ 0.743f, 0.0f, 0.218f, 0.0f, 1.0f,
+};
+
+static const float data25[389 * GP_PRIM_DATABUF_SIZE] = {
+ -0.284f, 0.0f, -0.444f, 0.0f, 1.0f, -0.285f, 0.0f, -0.448f, 0.0f, 1.0f, -0.285f, 0.0f, -0.45f, 0.0f, 1.0f, -0.286f, 0.0f, -0.454f, 0.0f, 1.0f,
+ -0.286f, 0.0f, -0.457f, 0.0f, 1.0f, -0.287f, 0.0f, -0.46f, 0.0f, 1.0f, -0.288f, 0.0f, -0.463f, 0.0f, 1.0f, -0.289f, 0.0f, -0.466f, 0.0f, 1.0f,
+ -0.289f, 0.0f, -0.47f, 0.0f, 1.0f, -0.29f, 0.0f, -0.473f, 0.0f, 1.0f, -0.291f, 0.0f, -0.476f, 0.0f, 1.0f, -0.292f, 0.0f, -0.48f, 0.0f, 1.0f,
+ -0.293f, 0.0f, -0.484f, 0.0f, 1.0f, -0.294f, 0.0f, -0.487f, 0.0f, 1.0f, -0.295f, 0.0f, -0.491f, 0.0f, 1.0f, -0.296f, 0.0f, -0.494f, 0.0f, 1.0f,
+ -0.297f, 0.0f, -0.498f, 0.0f, 1.0f, -0.298f, 0.0f, -0.502f, 0.0f, 1.0f, -0.299f, 0.0f, -0.505f, 0.0f, 1.0f, -0.3f, 0.0f, -0.509f, 0.0f, 1.0f,
+ -0.301f, 0.0f, -0.513f, 0.0f, 1.0f, -0.302f, 0.0f, -0.517f, 0.0f, 1.0f, -0.303f, 0.0f, -0.52f, 0.0f, 1.0f, -0.304f, 0.0f, -0.524f, 0.0f, 1.0f,
+ -0.305f, 0.0f, -0.528f, 0.0f, 1.0f, -0.306f, 0.0f, -0.532f, 0.0f, 1.0f, -0.307f, 0.0f, -0.535f, 0.0f, 1.0f, -0.308f, 0.0f, -0.539f, 0.0f, 1.0f,
+ -0.309f, 0.0f, -0.543f, 0.0f, 1.0f, -0.31f, 0.0f, -0.547f, 0.0f, 1.0f, -0.311f, 0.0f, -0.55f, 0.0f, 1.0f, -0.312f, 0.0f, -0.554f, 0.0f, 1.0f,
+ -0.313f, 0.0f, -0.558f, 0.0f, 1.0f, -0.314f, 0.0f, -0.562f, 0.0f, 1.0f, -0.315f, 0.0f, -0.565f, 0.0f, 1.0f, -0.316f, 0.0f, -0.569f, 0.0f, 1.0f,
+ -0.317f, 0.0f, -0.573f, 0.0f, 1.0f, -0.318f, 0.0f, -0.576f, 0.0f, 1.0f, -0.319f, 0.0f, -0.58f, 0.0f, 1.0f, -0.32f, 0.0f, -0.583f, 0.0f, 1.0f,
+ -0.321f, 0.0f, -0.587f, 0.0f, 1.0f, -0.322f, 0.0f, -0.591f, 0.0f, 1.0f, -0.323f, 0.0f, -0.594f, 0.0f, 1.0f, -0.323f, 0.0f, -0.598f, 0.0f, 1.0f,
+ -0.324f, 0.0f, -0.601f, 0.0f, 1.0f, -0.325f, 0.0f, -0.605f, 0.0f, 1.0f, -0.326f, 0.0f, -0.608f, 0.0f, 1.0f, -0.326f, 0.0f, -0.612f, 0.0f, 1.0f,
+ -0.327f, 0.0f, -0.615f, 0.0f, 1.0f, -0.328f, 0.0f, -0.619f, 0.0f, 1.0f, -0.328f, 0.0f, -0.622f, 0.0f, 1.0f, -0.329f, 0.0f, -0.625f, 0.0f, 1.0f,
+ -0.33f, 0.0f, -0.629f, 0.0f, 1.0f, -0.33f, 0.0f, -0.632f, 0.0f, 1.0f, -0.331f, 0.0f, -0.635f, 0.001f, 1.0f, -0.331f, 0.0f, -0.639f, 0.001f, 1.0f,
+ -0.332f, 0.0f, -0.642f, 0.002f, 1.0f, -0.332f, 0.0f, -0.645f, 0.002f, 1.0f, -0.333f, 0.0f, -0.649f, 0.003f, 1.0f, -0.333f, 0.0f, -0.652f, 0.005f, 1.0f,
+ -0.334f, 0.0f, -0.655f, 0.006f, 1.0f, -0.334f, 0.0f, -0.658f, 0.009f, 1.0f, -0.335f, 0.0f, -0.662f, 0.011f, 1.0f, -0.335f, 0.0f, -0.665f, 0.015f, 1.0f,
+ -0.335f, 0.0f, -0.668f, 0.019f, 1.0f, -0.336f, 0.0f, -0.672f, 0.024f, 1.0f, -0.336f, 0.0f, -0.675f, 0.031f, 1.0f, -0.337f, 0.0f, -0.678f, 0.038f, 1.0f,
+ -0.337f, 0.0f, -0.682f, 0.046f, 1.0f, -0.337f, 0.0f, -0.685f, 0.056f, 1.0f, -0.338f, 0.0f, -0.689f, 0.067f, 1.0f, -0.338f, 0.0f, -0.692f, 0.079f, 1.0f,
+ -0.338f, 0.0f, -0.696f, 0.093f, 1.0f, -0.339f, 0.0f, -0.699f, 0.107f, 1.0f, -0.339f, 0.0f, -0.703f, 0.123f, 1.0f, -0.34f, 0.0f, -0.706f, 0.139f, 1.0f,
+ -0.34f, 0.0f, -0.71f, 0.157f, 1.0f, -0.34f, 0.0f, -0.714f, 0.174f, 1.0f, -0.34f, 0.0f, -0.717f, 0.193f, 1.0f, -0.341f, 0.0f, -0.721f, 0.211f, 1.0f,
+ -0.341f, 0.0f, -0.725f, 0.23f, 1.0f, -0.341f, 0.0f, -0.729f, 0.248f, 1.0f, -0.342f, 0.0f, -0.732f, 0.266f, 1.0f, -0.342f, 0.0f, -0.736f, 0.284f, 1.0f,
+ -0.342f, 0.0f, -0.74f, 0.302f, 1.0f, -0.342f, 0.0f, -0.744f, 0.318f, 1.0f, -0.342f, 0.0f, -0.748f, 0.334f, 1.0f, -0.342f, 0.0f, -0.752f, 0.349f, 1.0f,
+ -0.343f, 0.0f, -0.756f, 0.364f, 1.0f, -0.343f, 0.0f, -0.76f, 0.377f, 1.0f, -0.343f, 0.0f, -0.763f, 0.389f, 1.0f, -0.343f, 0.0f, -0.767f, 0.401f, 1.0f,
+ -0.343f, 0.0f, -0.771f, 0.411f, 1.0f, -0.343f, 0.0f, -0.775f, 0.421f, 1.0f, -0.342f, 0.0f, -0.779f, 0.429f, 1.0f, -0.342f, 0.0f, -0.783f, 0.437f, 1.0f,
+ -0.342f, 0.0f, -0.786f, 0.444f, 1.0f, -0.342f, 0.0f, -0.79f, 0.451f, 1.0f, -0.342f, 0.0f, -0.794f, 0.456f, 1.0f, -0.341f, 0.0f, -0.797f, 0.461f, 1.0f,
+ -0.341f, 0.0f, -0.801f, 0.466f, 1.0f, -0.34f, 0.0f, -0.805f, 0.469f, 1.0f, -0.34f, 0.0f, -0.808f, 0.473f, 1.0f, -0.339f, 0.0f, -0.812f, 0.476f, 1.0f,
+ -0.339f, 0.0f, -0.815f, 0.478f, 1.0f, -0.338f, 0.0f, -0.818f, 0.48f, 1.0f, -0.338f, 0.0f, -0.822f, 0.482f, 1.0f, -0.337f, 0.0f, -0.825f, 0.483f, 1.0f,
+ -0.336f, 0.0f, -0.828f, 0.484f, 1.0f, -0.335f, 0.0f, -0.831f, 0.485f, 1.0f, -0.334f, 0.0f, -0.834f, 0.486f, 1.0f, -0.333f, 0.0f, -0.837f, 0.487f, 1.0f,
+ -0.332f, 0.0f, -0.84f, 0.487f, 1.0f, -0.331f, 0.0f, -0.843f, 0.487f, 1.0f, -0.33f, 0.0f, -0.846f, 0.488f, 1.0f, -0.329f, 0.0f, -0.849f, 0.488f, 1.0f,
+ -0.328f, 0.0f, -0.852f, 0.488f, 1.0f, -0.326f, 0.0f, -0.855f, 0.488f, 1.0f, -0.325f, 0.0f, -0.857f, 0.488f, 1.0f, -0.324f, 0.0f, -0.86f, 0.488f, 1.0f,
+ -0.322f, 0.0f, -0.863f, 0.488f, 1.0f, -0.321f, 0.0f, -0.865f, 0.488f, 1.0f, -0.319f, 0.0f, -0.868f, 0.488f, 1.0f, -0.318f, 0.0f, -0.871f, 0.488f, 1.0f,
+ -0.316f, 0.0f, -0.873f, 0.489f, 1.0f, -0.314f, 0.0f, -0.876f, 0.489f, 1.0f, -0.312f, 0.0f, -0.878f, 0.489f, 1.0f, -0.311f, 0.0f, -0.881f, 0.489f, 1.0f,
+ -0.309f, 0.0f, -0.883f, 0.489f, 1.0f, -0.307f, 0.0f, -0.885f, 0.489f, 1.0f, -0.305f, 0.0f, -0.888f, 0.49f, 1.0f, -0.303f, 0.0f, -0.89f, 0.491f, 1.0f,
+ -0.301f, 0.0f, -0.892f, 0.491f, 1.0f, -0.298f, 0.0f, -0.894f, 0.492f, 1.0f, -0.296f, 0.0f, -0.897f, 0.494f, 1.0f, -0.294f, 0.0f, -0.899f, 0.495f, 1.0f,
+ -0.292f, 0.0f, -0.901f, 0.497f, 1.0f, -0.289f, 0.0f, -0.903f, 0.5f, 1.0f, -0.287f, 0.0f, -0.905f, 0.502f, 1.0f, -0.284f, 0.0f, -0.907f, 0.505f, 1.0f,
+ -0.282f, 0.0f, -0.909f, 0.509f, 1.0f, -0.279f, 0.0f, -0.912f, 0.512f, 1.0f, -0.277f, 0.0f, -0.914f, 0.517f, 1.0f, -0.274f, 0.0f, -0.916f, 0.521f, 1.0f,
+ -0.271f, 0.0f, -0.918f, 0.526f, 1.0f, -0.269f, 0.0f, -0.919f, 0.531f, 1.0f, -0.266f, 0.0f, -0.921f, 0.537f, 1.0f, -0.263f, 0.0f, -0.923f, 0.543f, 1.0f,
+ -0.26f, 0.0f, -0.925f, 0.548f, 1.0f, -0.257f, 0.0f, -0.927f, 0.554f, 1.0f, -0.255f, 0.0f, -0.929f, 0.56f, 1.0f, -0.252f, 0.0f, -0.931f, 0.566f, 1.0f,
+ -0.249f, 0.0f, -0.932f, 0.571f, 1.0f, -0.246f, 0.0f, -0.934f, 0.577f, 1.0f, -0.243f, 0.0f, -0.936f, 0.582f, 1.0f, -0.24f, 0.0f, -0.938f, 0.587f, 1.0f,
+ -0.237f, 0.0f, -0.939f, 0.592f, 1.0f, -0.234f, 0.0f, -0.941f, 0.597f, 1.0f, -0.231f, 0.0f, -0.943f, 0.601f, 1.0f, -0.228f, 0.0f, -0.944f, 0.605f, 1.0f,
+ -0.225f, 0.0f, -0.946f, 0.609f, 1.0f, -0.222f, 0.0f, -0.948f, 0.613f, 1.0f, -0.219f, 0.0f, -0.949f, 0.617f, 1.0f, -0.216f, 0.0f, -0.951f, 0.62f, 1.0f,
+ -0.213f, 0.0f, -0.953f, 0.624f, 1.0f, -0.21f, 0.0f, -0.954f, 0.627f, 1.0f, -0.207f, 0.0f, -0.956f, 0.63f, 1.0f, -0.204f, 0.0f, -0.958f, 0.633f, 1.0f,
+ -0.201f, 0.0f, -0.959f, 0.636f, 1.0f, -0.198f, 0.0f, -0.961f, 0.639f, 1.0f, -0.195f, 0.0f, -0.962f, 0.641f, 1.0f, -0.191f, 0.0f, -0.964f, 0.643f, 1.0f,
+ -0.188f, 0.0f, -0.965f, 0.646f, 1.0f, -0.185f, 0.0f, -0.967f, 0.648f, 1.0f, -0.181f, 0.0f, -0.968f, 0.649f, 1.0f, -0.178f, 0.0f, -0.969f, 0.651f, 1.0f,
+ -0.175f, 0.0f, -0.971f, 0.653f, 1.0f, -0.171f, 0.0f, -0.972f, 0.654f, 1.0f, -0.168f, 0.0f, -0.973f, 0.655f, 1.0f, -0.165f, 0.0f, -0.974f, 0.657f, 1.0f,
+ -0.161f, 0.0f, -0.976f, 0.658f, 1.0f, -0.158f, 0.0f, -0.977f, 0.659f, 1.0f, -0.154f, 0.0f, -0.978f, 0.66f, 1.0f, -0.151f, 0.0f, -0.979f, 0.661f, 1.0f,
+ -0.148f, 0.0f, -0.98f, 0.662f, 1.0f, -0.144f, 0.0f, -0.981f, 0.664f, 1.0f, -0.141f, 0.0f, -0.982f, 0.665f, 1.0f, -0.137f, 0.0f, -0.983f, 0.667f, 1.0f,
+ -0.134f, 0.0f, -0.984f, 0.669f, 1.0f, -0.13f, 0.0f, -0.985f, 0.671f, 1.0f, -0.127f, 0.0f, -0.986f, 0.673f, 1.0f, -0.124f, 0.0f, -0.987f, 0.675f, 1.0f,
+ -0.12f, 0.0f, -0.988f, 0.678f, 1.0f, -0.117f, 0.0f, -0.989f, 0.68f, 1.0f, -0.113f, 0.0f, -0.99f, 0.683f, 1.0f, -0.11f, 0.0f, -0.991f, 0.685f, 1.0f,
+ -0.107f, 0.0f, -0.992f, 0.688f, 1.0f, -0.103f, 0.0f, -0.992f, 0.691f, 1.0f, -0.1f, 0.0f, -0.993f, 0.693f, 1.0f, -0.097f, 0.0f, -0.994f, 0.696f, 1.0f,
+ -0.093f, 0.0f, -0.995f, 0.698f, 1.0f, -0.09f, 0.0f, -0.996f, 0.701f, 1.0f, -0.087f, 0.0f, -0.997f, 0.703f, 1.0f, -0.084f, 0.0f, -0.997f, 0.705f, 1.0f,
+ -0.08f, 0.0f, -0.998f, 0.707f, 1.0f, -0.077f, 0.0f, -0.999f, 0.708f, 1.0f, -0.074f, 0.0f, -1.0f, 0.71f, 1.0f, -0.07f, 0.0f, -1.0f, 0.712f, 1.0f,
+ -0.067f, 0.0f, -1.001f, 0.713f, 1.0f, -0.063f, 0.0f, -1.002f, 0.715f, 1.0f, -0.06f, 0.0f, -1.002f, 0.717f, 1.0f, -0.056f, 0.0f, -1.003f, 0.718f, 1.0f,
+ -0.053f, 0.0f, -1.003f, 0.72f, 1.0f, -0.049f, 0.0f, -1.004f, 0.723f, 1.0f, -0.045f, 0.0f, -1.004f, 0.725f, 1.0f, -0.041f, 0.0f, -1.005f, 0.728f, 1.0f,
+ -0.038f, 0.0f, -1.005f, 0.73f, 1.0f, -0.034f, 0.0f, -1.006f, 0.733f, 1.0f, -0.03f, 0.0f, -1.006f, 0.736f, 1.0f, -0.026f, 0.0f, -1.007f, 0.738f, 1.0f,
+ -0.022f, 0.0f, -1.007f, 0.741f, 1.0f, -0.018f, 0.0f, -1.007f, 0.743f, 1.0f, -0.014f, 0.0f, -1.008f, 0.746f, 1.0f, -0.01f, 0.0f, -1.008f, 0.748f, 1.0f,
+ -0.006f, 0.0f, -1.009f, 0.75f, 1.0f, -0.001f, 0.0f, -1.009f, 0.752f, 1.0f, 0.003f, 0.0f, -1.009f, 0.754f, 1.0f, 0.007f, 0.0f, -1.01f, 0.755f, 1.0f,
+ 0.011f, 0.0f, -1.01f, 0.757f, 1.0f, 0.015f, 0.0f, -1.01f, 0.758f, 1.0f, 0.02f, 0.0f, -1.011f, 0.759f, 1.0f, 0.024f, 0.0f, -1.011f, 0.76f, 1.0f,
+ 0.028f, 0.0f, -1.011f, 0.761f, 1.0f, 0.033f, 0.0f, -1.011f, 0.761f, 1.0f, 0.037f, 0.0f, -1.012f, 0.762f, 1.0f, 0.041f, 0.0f, -1.012f, 0.762f, 1.0f,
+ 0.045f, 0.0f, -1.012f, 0.763f, 1.0f, 0.05f, 0.0f, -1.012f, 0.763f, 1.0f, 0.054f, 0.0f, -1.012f, 0.764f, 1.0f, 0.058f, 0.0f, -1.013f, 0.764f, 1.0f,
+ 0.062f, 0.0f, -1.013f, 0.764f, 1.0f, 0.066f, 0.0f, -1.013f, 0.764f, 1.0f, 0.071f, 0.0f, -1.013f, 0.764f, 1.0f, 0.075f, 0.0f, -1.013f, 0.765f, 1.0f,
+ 0.079f, 0.0f, -1.013f, 0.765f, 1.0f, 0.083f, 0.0f, -1.013f, 0.765f, 1.0f, 0.087f, 0.0f, -1.013f, 0.765f, 1.0f, 0.091f, 0.0f, -1.013f, 0.765f, 1.0f,
+ 0.095f, 0.0f, -1.013f, 0.765f, 1.0f, 0.099f, 0.0f, -1.013f, 0.766f, 1.0f, 0.103f, 0.0f, -1.013f, 0.766f, 1.0f, 0.108f, 0.0f, -1.012f, 0.766f, 1.0f,
+ 0.112f, 0.0f, -1.012f, 0.766f, 1.0f, 0.116f, 0.0f, -1.012f, 0.766f, 1.0f, 0.119f, 0.0f, -1.012f, 0.767f, 1.0f, 0.123f, 0.0f, -1.011f, 0.767f, 1.0f,
+ 0.127f, 0.0f, -1.011f, 0.767f, 1.0f, 0.131f, 0.0f, -1.01f, 0.767f, 1.0f, 0.135f, 0.0f, -1.01f, 0.767f, 1.0f, 0.139f, 0.0f, -1.009f, 0.768f, 1.0f,
+ 0.143f, 0.0f, -1.009f, 0.768f, 1.0f, 0.147f, 0.0f, -1.008f, 0.768f, 1.0f, 0.151f, 0.0f, -1.007f, 0.769f, 1.0f, 0.154f, 0.0f, -1.007f, 0.769f, 1.0f,
+ 0.158f, 0.0f, -1.006f, 0.769f, 1.0f, 0.162f, 0.0f, -1.005f, 0.769f, 1.0f, 0.166f, 0.0f, -1.004f, 0.77f, 1.0f, 0.17f, 0.0f, -1.003f, 0.77f, 1.0f,
+ 0.173f, 0.0f, -1.003f, 0.77f, 1.0f, 0.177f, 0.0f, -1.002f, 0.771f, 1.0f, 0.181f, 0.0f, -1.001f, 0.771f, 1.0f, 0.184f, 0.0f, -1.0f, 0.772f, 1.0f,
+ 0.188f, 0.0f, -0.999f, 0.772f, 1.0f, 0.192f, 0.0f, -0.998f, 0.773f, 1.0f, 0.195f, 0.0f, -0.997f, 0.773f, 1.0f, 0.199f, 0.0f, -0.996f, 0.774f, 1.0f,
+ 0.202f, 0.0f, -0.995f, 0.774f, 1.0f, 0.206f, 0.0f, -0.994f, 0.775f, 1.0f, 0.209f, 0.0f, -0.993f, 0.776f, 1.0f, 0.213f, 0.0f, -0.992f, 0.776f, 1.0f,
+ 0.216f, 0.0f, -0.991f, 0.777f, 1.0f, 0.22f, 0.0f, -0.99f, 0.777f, 1.0f, 0.223f, 0.0f, -0.988f, 0.778f, 1.0f, 0.227f, 0.0f, -0.987f, 0.778f, 1.0f,
+ 0.23f, 0.0f, -0.986f, 0.778f, 1.0f, 0.233f, 0.0f, -0.985f, 0.779f, 1.0f, 0.237f, 0.0f, -0.983f, 0.779f, 1.0f, 0.24f, 0.0f, -0.982f, 0.779f, 1.0f,
+ 0.243f, 0.0f, -0.981f, 0.779f, 1.0f, 0.246f, 0.0f, -0.979f, 0.778f, 1.0f, 0.249f, 0.0f, -0.978f, 0.778f, 1.0f, 0.252f, 0.0f, -0.976f, 0.777f, 1.0f,
+ 0.255f, 0.0f, -0.975f, 0.777f, 1.0f, 0.258f, 0.0f, -0.973f, 0.776f, 1.0f, 0.261f, 0.0f, -0.972f, 0.775f, 1.0f, 0.264f, 0.0f, -0.97f, 0.773f, 1.0f,
+ 0.267f, 0.0f, -0.968f, 0.772f, 1.0f, 0.269f, 0.0f, -0.967f, 0.77f, 1.0f, 0.272f, 0.0f, -0.965f, 0.769f, 1.0f, 0.275f, 0.0f, -0.963f, 0.767f, 1.0f,
+ 0.277f, 0.0f, -0.961f, 0.765f, 1.0f, 0.279f, 0.0f, -0.959f, 0.763f, 1.0f, 0.282f, 0.0f, -0.957f, 0.761f, 1.0f, 0.284f, 0.0f, -0.955f, 0.759f, 1.0f,
+ 0.286f, 0.0f, -0.953f, 0.756f, 1.0f, 0.288f, 0.0f, -0.951f, 0.754f, 1.0f, 0.29f, 0.0f, -0.948f, 0.752f, 1.0f, 0.292f, 0.0f, -0.946f, 0.749f, 1.0f,
+ 0.294f, 0.0f, -0.944f, 0.746f, 1.0f, 0.296f, 0.0f, -0.941f, 0.744f, 1.0f, 0.298f, 0.0f, -0.939f, 0.741f, 1.0f, 0.3f, 0.0f, -0.937f, 0.738f, 1.0f,
+ 0.302f, 0.0f, -0.934f, 0.736f, 1.0f, 0.303f, 0.0f, -0.932f, 0.733f, 1.0f, 0.305f, 0.0f, -0.929f, 0.73f, 1.0f, 0.306f, 0.0f, -0.926f, 0.727f, 1.0f,
+ 0.308f, 0.0f, -0.924f, 0.724f, 1.0f, 0.309f, 0.0f, -0.921f, 0.721f, 1.0f, 0.311f, 0.0f, -0.918f, 0.719f, 1.0f, 0.312f, 0.0f, -0.916f, 0.716f, 1.0f,
+ 0.313f, 0.0f, -0.913f, 0.713f, 1.0f, 0.315f, 0.0f, -0.91f, 0.71f, 1.0f, 0.316f, 0.0f, -0.907f, 0.707f, 1.0f, 0.317f, 0.0f, -0.904f, 0.704f, 1.0f,
+ 0.318f, 0.0f, -0.901f, 0.7f, 1.0f, 0.319f, 0.0f, -0.898f, 0.697f, 1.0f, 0.32f, 0.0f, -0.895f, 0.693f, 1.0f, 0.321f, 0.0f, -0.892f, 0.69f, 1.0f,
+ 0.322f, 0.0f, -0.889f, 0.686f, 1.0f, 0.323f, 0.0f, -0.886f, 0.681f, 1.0f, 0.324f, 0.0f, -0.883f, 0.677f, 1.0f, 0.325f, 0.0f, -0.88f, 0.672f, 1.0f,
+ 0.326f, 0.0f, -0.876f, 0.667f, 1.0f, 0.326f, 0.0f, -0.873f, 0.661f, 1.0f, 0.327f, 0.0f, -0.87f, 0.655f, 1.0f, 0.328f, 0.0f, -0.867f, 0.649f, 1.0f,
+ 0.329f, 0.0f, -0.864f, 0.643f, 1.0f, 0.329f, 0.0f, -0.861f, 0.637f, 1.0f, 0.33f, 0.0f, -0.857f, 0.63f, 1.0f, 0.331f, 0.0f, -0.854f, 0.624f, 1.0f,
+ 0.331f, 0.0f, -0.851f, 0.618f, 1.0f, 0.332f, 0.0f, -0.848f, 0.613f, 1.0f, 0.333f, 0.0f, -0.845f, 0.607f, 1.0f, 0.333f, 0.0f, -0.841f, 0.603f, 1.0f,
+ 0.334f, 0.0f, -0.838f, 0.598f, 1.0f, 0.334f, 0.0f, -0.835f, 0.594f, 1.0f, 0.335f, 0.0f, -0.832f, 0.591f, 1.0f, 0.335f, 0.0f, -0.828f, 0.588f, 1.0f,
+ 0.335f, 0.0f, -0.825f, 0.586f, 1.0f, 0.336f, 0.0f, -0.821f, 0.584f, 1.0f, 0.336f, 0.0f, -0.818f, 0.582f, 1.0f, 0.336f, 0.0f, -0.814f, 0.581f, 1.0f,
+ 0.337f, 0.0f, -0.811f, 0.58f, 1.0f, 0.337f, 0.0f, -0.807f, 0.58f, 1.0f, 0.337f, 0.0f, -0.803f, 0.579f, 1.0f, 0.337f, 0.0f, -0.799f, 0.579f, 1.0f,
+ 0.337f, 0.0f, -0.795f, 0.578f, 1.0f, 0.337f, 0.0f, -0.79f, 0.578f, 1.0f, 0.337f, 0.0f, -0.786f, 0.578f, 1.0f, 0.338f, 0.0f, -0.782f, 0.577f, 1.0f,
+ 0.338f, 0.0f, -0.777f, 0.576f, 1.0f, 0.337f, 0.0f, -0.772f, 0.574f, 1.0f, 0.337f, 0.0f, -0.767f, 0.572f, 1.0f, 0.337f, 0.0f, -0.762f, 0.569f, 1.0f,
+ 0.337f, 0.0f, -0.756f, 0.565f, 1.0f, 0.337f, 0.0f, -0.751f, 0.559f, 1.0f, 0.337f, 0.0f, -0.745f, 0.553f, 1.0f, 0.336f, 0.0f, -0.739f, 0.544f, 1.0f,
+ 0.336f, 0.0f, -0.732f, 0.534f, 1.0f, 0.335f, 0.0f, -0.725f, 0.521f, 1.0f, 0.334f, 0.0f, -0.718f, 0.505f, 1.0f, 0.333f, 0.0f, -0.711f, 0.487f, 1.0f,
+ 0.332f, 0.0f, -0.703f, 0.466f, 1.0f, 0.331f, 0.0f, -0.694f, 0.441f, 1.0f, 0.33f, 0.0f, -0.686f, 0.413f, 1.0f, 0.328f, 0.0f, -0.677f, 0.383f, 1.0f,
+ 0.326f, 0.0f, -0.667f, 0.35f, 1.0f, 0.325f, 0.0f, -0.657f, 0.316f, 1.0f, 0.323f, 0.0f, -0.647f, 0.281f, 1.0f, 0.32f, 0.0f, -0.636f, 0.246f, 1.0f,
+ 0.318f, 0.0f, -0.625f, 0.212f, 1.0f, 0.316f, 0.0f, -0.614f, 0.18f, 1.0f, 0.313f, 0.0f, -0.603f, 0.149f, 1.0f, 0.311f, 0.0f, -0.592f, 0.12f, 1.0f,
+ 0.308f, 0.0f, -0.581f, 0.093f, 1.0f, 0.306f, 0.0f, -0.57f, 0.069f, 1.0f, 0.303f, 0.0f, -0.559f, 0.046f, 1.0f, 0.301f, 0.0f, -0.55f, 0.027f, 1.0f,
+ 0.298f, 0.0f, -0.537f, 0.0f, 1.0f,
+};
+
+static const float data26[41 * GP_PRIM_DATABUF_SIZE] = {
+ -0.104f, 0.0f, -0.795f, 0.258f, 1.0f, -0.1f, 0.0f, -0.799f, 0.28f, 1.0f, -0.097f, 0.0f, -0.801f, 0.294f, 1.0f, -0.094f, 0.0f, -0.805f, 0.312f, 1.0f,
+ -0.09f, 0.0f, -0.808f, 0.328f, 1.0f, -0.086f, 0.0f, -0.811f, 0.345f, 1.0f, -0.082f, 0.0f, -0.815f, 0.361f, 1.0f, -0.078f, 0.0f, -0.818f, 0.377f, 1.0f,
+ -0.073f, 0.0f, -0.821f, 0.392f, 1.0f, -0.068f, 0.0f, -0.824f, 0.407f, 1.0f, -0.063f, 0.0f, -0.827f, 0.421f, 1.0f, -0.057f, 0.0f, -0.83f, 0.435f, 1.0f,
+ -0.051f, 0.0f, -0.833f, 0.448f, 1.0f, -0.045f, 0.0f, -0.835f, 0.46f, 1.0f, -0.039f, 0.0f, -0.837f, 0.471f, 1.0f, -0.033f, 0.0f, -0.839f, 0.481f, 1.0f,
+ -0.026f, 0.0f, -0.841f, 0.491f, 1.0f, -0.019f, 0.0f, -0.842f, 0.5f, 1.0f, -0.012f, 0.0f, -0.843f, 0.508f, 1.0f, -0.005f, 0.0f, -0.843f, 0.515f, 1.0f,
+ 0.002f, 0.0f, -0.843f, 0.522f, 1.0f, 0.009f, 0.0f, -0.843f, 0.527f, 1.0f, 0.016f, 0.0f, -0.842f, 0.532f, 1.0f, 0.023f, 0.0f, -0.841f, 0.535f, 1.0f,
+ 0.03f, 0.0f, -0.839f, 0.538f, 1.0f, 0.037f, 0.0f, -0.837f, 0.538f, 1.0f, 0.044f, 0.0f, -0.835f, 0.537f, 1.0f, 0.05f, 0.0f, -0.833f, 0.532f, 1.0f,
+ 0.056f, 0.0f, -0.83f, 0.524f, 1.0f, 0.062f, 0.0f, -0.827f, 0.513f, 1.0f, 0.068f, 0.0f, -0.823f, 0.496f, 1.0f, 0.074f, 0.0f, -0.82f, 0.474f, 1.0f,
+ 0.079f, 0.0f, -0.817f, 0.446f, 1.0f, 0.084f, 0.0f, -0.813f, 0.411f, 1.0f, 0.089f, 0.0f, -0.809f, 0.37f, 1.0f, 0.093f, 0.0f, -0.806f, 0.323f, 1.0f,
+ 0.098f, 0.0f, -0.802f, 0.269f, 1.0f, 0.102f, 0.0f, -0.798f, 0.211f, 1.0f, 0.106f, 0.0f, -0.795f, 0.146f, 1.0f, 0.109f, 0.0f, -0.792f, 0.089f, 1.0f,
+ 0.114f, 0.0f, -0.787f, 0.0f, 1.0f,
+};
+
+static const float data27[77 * GP_PRIM_DATABUF_SIZE] = {
+ -0.105f, 0.0f, -0.259f, 0.214f, 1.0f, -0.103f, 0.0f, -0.253f, 0.263f, 1.0f, -0.101f, 0.0f, -0.249f, 0.291f, 1.0f, -0.099f, 0.0f, -0.244f, 0.324f, 1.0f,
+ -0.098f, 0.0f, -0.24f, 0.351f, 1.0f, -0.096f, 0.0f, -0.235f, 0.376f, 1.0f, -0.094f, 0.0f, -0.231f, 0.397f, 1.0f, -0.092f, 0.0f, -0.227f, 0.416f, 1.0f,
+ -0.09f, 0.0f, -0.222f, 0.432f, 1.0f, -0.088f, 0.0f, -0.218f, 0.446f, 1.0f, -0.086f, 0.0f, -0.215f, 0.458f, 1.0f, -0.084f, 0.0f, -0.211f, 0.469f, 1.0f,
+ -0.082f, 0.0f, -0.208f, 0.478f, 1.0f, -0.079f, 0.0f, -0.205f, 0.486f, 1.0f, -0.077f, 0.0f, -0.203f, 0.494f, 1.0f, -0.075f, 0.0f, -0.2f, 0.501f, 1.0f,
+ -0.073f, 0.0f, -0.198f, 0.508f, 1.0f, -0.071f, 0.0f, -0.197f, 0.515f, 1.0f, -0.068f, 0.0f, -0.195f, 0.521f, 1.0f, -0.066f, 0.0f, -0.194f, 0.528f, 1.0f,
+ -0.064f, 0.0f, -0.194f, 0.534f, 1.0f, -0.061f, 0.0f, -0.194f, 0.54f, 1.0f, -0.059f, 0.0f, -0.194f, 0.546f, 1.0f, -0.056f, 0.0f, -0.194f, 0.551f, 1.0f,
+ -0.054f, 0.0f, -0.195f, 0.555f, 1.0f, -0.051f, 0.0f, -0.196f, 0.559f, 1.0f, -0.049f, 0.0f, -0.198f, 0.562f, 1.0f, -0.046f, 0.0f, -0.2f, 0.565f, 1.0f,
+ -0.044f, 0.0f, -0.201f, 0.567f, 1.0f, -0.041f, 0.0f, -0.204f, 0.568f, 1.0f, -0.039f, 0.0f, -0.206f, 0.569f, 1.0f, -0.036f, 0.0f, -0.208f, 0.57f, 1.0f,
+ -0.034f, 0.0f, -0.21f, 0.571f, 1.0f, -0.032f, 0.0f, -0.213f, 0.571f, 1.0f, -0.029f, 0.0f, -0.215f, 0.571f, 1.0f, -0.027f, 0.0f, -0.217f, 0.572f, 1.0f,
+ -0.024f, 0.0f, -0.219f, 0.572f, 1.0f, -0.022f, 0.0f, -0.221f, 0.572f, 1.0f, -0.019f, 0.0f, -0.222f, 0.572f, 1.0f, -0.016f, 0.0f, -0.224f, 0.572f, 1.0f,
+ -0.013f, 0.0f, -0.225f, 0.572f, 1.0f, -0.01f, 0.0f, -0.226f, 0.573f, 1.0f, -0.007f, 0.0f, -0.227f, 0.573f, 1.0f, -0.004f, 0.0f, -0.227f, 0.573f, 1.0f,
+ -0.001f, 0.0f, -0.227f, 0.574f, 1.0f, 0.002f, 0.0f, -0.227f, 0.575f, 1.0f, 0.005f, 0.0f, -0.227f, 0.576f, 1.0f, 0.008f, 0.0f, -0.226f, 0.577f, 1.0f,
+ 0.011f, 0.0f, -0.225f, 0.578f, 1.0f, 0.015f, 0.0f, -0.224f, 0.579f, 1.0f, 0.018f, 0.0f, -0.222f, 0.58f, 1.0f, 0.021f, 0.0f, -0.221f, 0.581f, 1.0f,
+ 0.024f, 0.0f, -0.219f, 0.582f, 1.0f, 0.027f, 0.0f, -0.217f, 0.582f, 1.0f, 0.03f, 0.0f, -0.215f, 0.583f, 1.0f, 0.033f, 0.0f, -0.213f, 0.583f, 1.0f,
+ 0.036f, 0.0f, -0.212f, 0.583f, 1.0f, 0.039f, 0.0f, -0.21f, 0.583f, 1.0f, 0.042f, 0.0f, -0.208f, 0.583f, 1.0f, 0.045f, 0.0f, -0.207f, 0.583f, 1.0f,
+ 0.048f, 0.0f, -0.205f, 0.583f, 1.0f, 0.051f, 0.0f, -0.204f, 0.583f, 1.0f, 0.054f, 0.0f, -0.203f, 0.583f, 1.0f, 0.058f, 0.0f, -0.203f, 0.583f, 1.0f,
+ 0.061f, 0.0f, -0.202f, 0.583f, 1.0f, 0.064f, 0.0f, -0.202f, 0.574f, 1.0f, 0.067f, 0.0f, -0.202f, 0.565f, 1.0f, 0.07f, 0.0f, -0.203f, 0.556f, 1.0f,
+ 0.073f, 0.0f, -0.203f, 0.547f, 1.0f, 0.075f, 0.0f, -0.204f, 0.515f, 1.0f, 0.078f, 0.0f, -0.204f, 0.483f, 1.0f, 0.08f, 0.0f, -0.205f, 0.451f, 1.0f,
+ 0.083f, 0.0f, -0.206f, 0.419f, 1.0f, 0.085f, 0.0f, -0.207f, 0.314f, 1.0f, 0.087f, 0.0f, -0.208f, 0.21f, 1.0f, 0.089f, 0.0f, -0.209f, 0.105f, 1.0f,
+ 0.091f, 0.0f, -0.21f, 0.0f, 1.0f,
+};
+
+static const float data28[257 * GP_PRIM_DATABUF_SIZE] = {
+ -0.637f, 0.0f, -0.172f, 0.0f, 1.0f, -0.641f, 0.0f, -0.172f, 0.0f, 1.0f, -0.643f, 0.0f, -0.172f, 0.0f, 1.0f, -0.646f, 0.0f, -0.172f, 0.0f, 1.0f,
+ -0.65f, 0.0f, -0.172f, 0.0f, 1.0f, -0.653f, 0.0f, -0.172f, 0.0f, 1.0f, -0.657f, 0.0f, -0.172f, 0.0f, 1.0f, -0.66f, 0.0f, -0.172f, 0.0f, 1.0f,
+ -0.664f, 0.0f, -0.171f, 0.0f, 1.0f, -0.668f, 0.0f, -0.171f, 0.0f, 1.0f, -0.672f, 0.0f, -0.171f, 0.0f, 1.0f, -0.677f, 0.0f, -0.171f, 0.0f, 1.0f,
+ -0.681f, 0.0f, -0.171f, 0.0f, 1.0f, -0.685f, 0.0f, -0.171f, 0.0f, 1.0f, -0.69f, 0.0f, -0.17f, 0.0f, 1.0f, -0.694f, 0.0f, -0.17f, 0.0f, 1.0f,
+ -0.699f, 0.0f, -0.17f, 0.0f, 1.0f, -0.704f, 0.0f, -0.169f, 0.0f, 1.0f, -0.708f, 0.0f, -0.169f, 0.0f, 1.0f, -0.713f, 0.0f, -0.168f, 0.0f, 1.0f,
+ -0.717f, 0.0f, -0.168f, 0.0f, 1.0f, -0.722f, 0.0f, -0.167f, 0.0f, 1.0f, -0.727f, 0.0f, -0.167f, 0.0f, 1.0f, -0.731f, 0.0f, -0.166f, 0.0f, 1.0f,
+ -0.735f, 0.0f, -0.166f, 0.0f, 1.0f, -0.74f, 0.0f, -0.165f, 0.0f, 1.0f, -0.744f, 0.0f, -0.164f, 0.0f, 1.0f, -0.749f, 0.0f, -0.163f, 0.0f, 1.0f,
+ -0.753f, 0.0f, -0.163f, 0.0f, 1.0f, -0.757f, 0.0f, -0.162f, 0.0f, 1.0f, -0.761f, 0.0f, -0.161f, 0.0f, 1.0f, -0.765f, 0.0f, -0.16f, 0.0f, 1.0f,
+ -0.769f, 0.0f, -0.159f, 0.0f, 1.0f, -0.773f, 0.0f, -0.158f, 0.0f, 1.0f, -0.777f, 0.0f, -0.157f, 0.0f, 1.0f, -0.781f, 0.0f, -0.156f, 0.001f, 1.0f,
+ -0.785f, 0.0f, -0.155f, 0.001f, 1.0f, -0.789f, 0.0f, -0.154f, 0.002f, 1.0f, -0.793f, 0.0f, -0.153f, 0.003f, 1.0f, -0.797f, 0.0f, -0.152f, 0.004f, 1.0f,
+ -0.801f, 0.0f, -0.15f, 0.005f, 1.0f, -0.805f, 0.0f, -0.149f, 0.006f, 1.0f, -0.81f, 0.0f, -0.147f, 0.008f, 1.0f, -0.814f, 0.0f, -0.146f, 0.009f, 1.0f,
+ -0.818f, 0.0f, -0.144f, 0.011f, 1.0f, -0.823f, 0.0f, -0.143f, 0.014f, 1.0f, -0.827f, 0.0f, -0.141f, 0.016f, 1.0f, -0.831f, 0.0f, -0.139f, 0.019f, 1.0f,
+ -0.836f, 0.0f, -0.138f, 0.022f, 1.0f, -0.84f, 0.0f, -0.136f, 0.024f, 1.0f, -0.844f, 0.0f, -0.135f, 0.026f, 1.0f, -0.849f, 0.0f, -0.133f, 0.027f, 1.0f,
+ -0.853f, 0.0f, -0.131f, 0.027f, 1.0f, -0.857f, 0.0f, -0.13f, 0.027f, 1.0f, -0.861f, 0.0f, -0.128f, 0.027f, 1.0f, -0.865f, 0.0f, -0.126f, 0.027f, 1.0f,
+ -0.868f, 0.0f, -0.125f, 0.026f, 1.0f, -0.872f, 0.0f, -0.123f, 0.025f, 1.0f, -0.876f, 0.0f, -0.121f, 0.025f, 1.0f, -0.879f, 0.0f, -0.119f, 0.024f, 1.0f,
+ -0.883f, 0.0f, -0.118f, 0.023f, 1.0f, -0.886f, 0.0f, -0.116f, 0.022f, 1.0f, -0.89f, 0.0f, -0.114f, 0.022f, 1.0f, -0.894f, 0.0f, -0.112f, 0.021f, 1.0f,
+ -0.898f, 0.0f, -0.11f, 0.022f, 1.0f, -0.901f, 0.0f, -0.107f, 0.022f, 1.0f, -0.905f, 0.0f, -0.105f, 0.024f, 1.0f, -0.909f, 0.0f, -0.103f, 0.026f, 1.0f,
+ -0.913f, 0.0f, -0.1f, 0.029f, 1.0f, -0.917f, 0.0f, -0.098f, 0.032f, 1.0f, -0.921f, 0.0f, -0.095f, 0.035f, 1.0f, -0.926f, 0.0f, -0.092f, 0.039f, 1.0f,
+ -0.93f, 0.0f, -0.09f, 0.043f, 1.0f, -0.934f, 0.0f, -0.087f, 0.047f, 1.0f, -0.938f, 0.0f, -0.084f, 0.051f, 1.0f, -0.942f, 0.0f, -0.081f, 0.055f, 1.0f,
+ -0.946f, 0.0f, -0.078f, 0.06f, 1.0f, -0.95f, 0.0f, -0.075f, 0.065f, 1.0f, -0.954f, 0.0f, -0.073f, 0.07f, 1.0f, -0.958f, 0.0f, -0.07f, 0.075f, 1.0f,
+ -0.961f, 0.0f, -0.067f, 0.081f, 1.0f, -0.965f, 0.0f, -0.064f, 0.087f, 1.0f, -0.968f, 0.0f, -0.061f, 0.092f, 1.0f, -0.972f, 0.0f, -0.058f, 0.098f, 1.0f,
+ -0.975f, 0.0f, -0.055f, 0.103f, 1.0f, -0.979f, 0.0f, -0.053f, 0.108f, 1.0f, -0.982f, 0.0f, -0.05f, 0.112f, 1.0f, -0.985f, 0.0f, -0.047f, 0.116f, 1.0f,
+ -0.988f, 0.0f, -0.045f, 0.12f, 1.0f, -0.991f, 0.0f, -0.042f, 0.123f, 1.0f, -0.994f, 0.0f, -0.039f, 0.126f, 1.0f, -0.997f, 0.0f, -0.037f, 0.129f, 1.0f,
+ -1.0f, 0.0f, -0.034f, 0.131f, 1.0f, -1.003f, 0.0f, -0.031f, 0.133f, 1.0f, -1.005f, 0.0f, -0.029f, 0.135f, 1.0f, -1.008f, 0.0f, -0.026f, 0.137f, 1.0f,
+ -1.01f, 0.0f, -0.024f, 0.139f, 1.0f, -1.013f, 0.0f, -0.021f, 0.141f, 1.0f, -1.016f, 0.0f, -0.018f, 0.143f, 1.0f, -1.018f, 0.0f, -0.016f, 0.144f, 1.0f,
+ -1.02f, 0.0f, -0.013f, 0.146f, 1.0f, -1.023f, 0.0f, -0.011f, 0.148f, 1.0f, -1.025f, 0.0f, -0.008f, 0.149f, 1.0f, -1.027f, 0.0f, -0.006f, 0.151f, 1.0f,
+ -1.029f, 0.0f, -0.003f, 0.152f, 1.0f, -1.032f, 0.0f, -0.001f, 0.154f, 1.0f, -1.034f, 0.0f, 0.001f, 0.154f, 1.0f, -1.036f, 0.0f, 0.004f, 0.155f, 1.0f,
+ -1.038f, 0.0f, 0.006f, 0.156f, 1.0f, -1.041f, 0.0f, 0.008f, 0.156f, 1.0f, -1.043f, 0.0f, 0.01f, 0.157f, 1.0f, -1.045f, 0.0f, 0.013f, 0.157f, 1.0f,
+ -1.047f, 0.0f, 0.015f, 0.157f, 1.0f, -1.049f, 0.0f, 0.018f, 0.158f, 1.0f, -1.051f, 0.0f, 0.02f, 0.158f, 1.0f, -1.053f, 0.0f, 0.023f, 0.158f, 1.0f,
+ -1.055f, 0.0f, 0.025f, 0.158f, 1.0f, -1.057f, 0.0f, 0.028f, 0.158f, 1.0f, -1.059f, 0.0f, 0.03f, 0.158f, 1.0f, -1.061f, 0.0f, 0.033f, 0.158f, 1.0f,
+ -1.063f, 0.0f, 0.036f, 0.158f, 1.0f, -1.065f, 0.0f, 0.038f, 0.158f, 1.0f, -1.067f, 0.0f, 0.041f, 0.158f, 1.0f, -1.069f, 0.0f, 0.044f, 0.157f, 1.0f,
+ -1.071f, 0.0f, 0.047f, 0.157f, 1.0f, -1.073f, 0.0f, 0.049f, 0.156f, 1.0f, -1.074f, 0.0f, 0.052f, 0.155f, 1.0f, -1.076f, 0.0f, 0.055f, 0.154f, 1.0f,
+ -1.078f, 0.0f, 0.058f, 0.153f, 1.0f, -1.08f, 0.0f, 0.061f, 0.152f, 1.0f, -1.082f, 0.0f, 0.064f, 0.15f, 1.0f, -1.083f, 0.0f, 0.067f, 0.148f, 1.0f,
+ -1.085f, 0.0f, 0.07f, 0.146f, 1.0f, -1.087f, 0.0f, 0.073f, 0.144f, 1.0f, -1.089f, 0.0f, 0.076f, 0.142f, 1.0f, -1.091f, 0.0f, 0.08f, 0.14f, 1.0f,
+ -1.092f, 0.0f, 0.083f, 0.138f, 1.0f, -1.094f, 0.0f, 0.086f, 0.136f, 1.0f, -1.096f, 0.0f, 0.09f, 0.135f, 1.0f, -1.097f, 0.0f, 0.093f, 0.134f, 1.0f,
+ -1.099f, 0.0f, 0.096f, 0.134f, 1.0f, -1.101f, 0.0f, 0.1f, 0.134f, 1.0f, -1.103f, 0.0f, 0.103f, 0.136f, 1.0f, -1.104f, 0.0f, 0.107f, 0.139f, 1.0f,
+ -1.106f, 0.0f, 0.111f, 0.144f, 1.0f, -1.107f, 0.0f, 0.114f, 0.15f, 1.0f, -1.109f, 0.0f, 0.118f, 0.158f, 1.0f, -1.11f, 0.0f, 0.122f, 0.167f, 1.0f,
+ -1.111f, 0.0f, 0.126f, 0.178f, 1.0f, -1.113f, 0.0f, 0.13f, 0.191f, 1.0f, -1.114f, 0.0f, 0.134f, 0.205f, 1.0f, -1.115f, 0.0f, 0.138f, 0.22f, 1.0f,
+ -1.116f, 0.0f, 0.142f, 0.237f, 1.0f, -1.117f, 0.0f, 0.146f, 0.254f, 1.0f, -1.118f, 0.0f, 0.15f, 0.272f, 1.0f, -1.119f, 0.0f, 0.155f, 0.291f, 1.0f,
+ -1.119f, 0.0f, 0.159f, 0.31f, 1.0f, -1.12f, 0.0f, 0.163f, 0.329f, 1.0f, -1.121f, 0.0f, 0.167f, 0.348f, 1.0f, -1.121f, 0.0f, 0.172f, 0.367f, 1.0f,
+ -1.122f, 0.0f, 0.176f, 0.386f, 1.0f, -1.122f, 0.0f, 0.18f, 0.405f, 1.0f, -1.123f, 0.0f, 0.184f, 0.423f, 1.0f, -1.123f, 0.0f, 0.189f, 0.441f, 1.0f,
+ -1.124f, 0.0f, 0.193f, 0.458f, 1.0f, -1.124f, 0.0f, 0.197f, 0.475f, 1.0f, -1.124f, 0.0f, 0.202f, 0.492f, 1.0f, -1.124f, 0.0f, 0.206f, 0.508f, 1.0f,
+ -1.125f, 0.0f, 0.21f, 0.524f, 1.0f, -1.125f, 0.0f, 0.214f, 0.539f, 1.0f, -1.125f, 0.0f, 0.218f, 0.554f, 1.0f, -1.124f, 0.0f, 0.223f, 0.568f, 1.0f,
+ -1.124f, 0.0f, 0.227f, 0.581f, 1.0f, -1.124f, 0.0f, 0.231f, 0.593f, 1.0f, -1.124f, 0.0f, 0.235f, 0.604f, 1.0f, -1.123f, 0.0f, 0.239f, 0.614f, 1.0f,
+ -1.123f, 0.0f, 0.243f, 0.624f, 1.0f, -1.122f, 0.0f, 0.247f, 0.632f, 1.0f, -1.122f, 0.0f, 0.251f, 0.64f, 1.0f, -1.121f, 0.0f, 0.255f, 0.646f, 1.0f,
+ -1.121f, 0.0f, 0.258f, 0.653f, 1.0f, -1.12f, 0.0f, 0.262f, 0.658f, 1.0f, -1.119f, 0.0f, 0.266f, 0.663f, 1.0f, -1.118f, 0.0f, 0.269f, 0.668f, 1.0f,
+ -1.117f, 0.0f, 0.272f, 0.673f, 1.0f, -1.117f, 0.0f, 0.276f, 0.678f, 1.0f, -1.116f, 0.0f, 0.279f, 0.682f, 1.0f, -1.115f, 0.0f, 0.282f, 0.687f, 1.0f,
+ -1.113f, 0.0f, 0.285f, 0.692f, 1.0f, -1.112f, 0.0f, 0.289f, 0.697f, 1.0f, -1.111f, 0.0f, 0.292f, 0.702f, 1.0f, -1.11f, 0.0f, 0.294f, 0.708f, 1.0f,
+ -1.109f, 0.0f, 0.297f, 0.713f, 1.0f, -1.108f, 0.0f, 0.3f, 0.718f, 1.0f, -1.106f, 0.0f, 0.303f, 0.724f, 1.0f, -1.105f, 0.0f, 0.306f, 0.73f, 1.0f,
+ -1.104f, 0.0f, 0.309f, 0.735f, 1.0f, -1.102f, 0.0f, 0.312f, 0.741f, 1.0f, -1.101f, 0.0f, 0.315f, 0.746f, 1.0f, -1.099f, 0.0f, 0.318f, 0.751f, 1.0f,
+ -1.098f, 0.0f, 0.321f, 0.756f, 1.0f, -1.096f, 0.0f, 0.323f, 0.761f, 1.0f, -1.094f, 0.0f, 0.326f, 0.766f, 1.0f, -1.093f, 0.0f, 0.329f, 0.771f, 1.0f,
+ -1.091f, 0.0f, 0.332f, 0.776f, 1.0f, -1.089f, 0.0f, 0.335f, 0.781f, 1.0f, -1.087f, 0.0f, 0.338f, 0.786f, 1.0f, -1.085f, 0.0f, 0.341f, 0.791f, 1.0f,
+ -1.082f, 0.0f, 0.344f, 0.797f, 1.0f, -1.08f, 0.0f, 0.347f, 0.802f, 1.0f, -1.078f, 0.0f, 0.349f, 0.808f, 1.0f, -1.075f, 0.0f, 0.352f, 0.814f, 1.0f,
+ -1.072f, 0.0f, 0.355f, 0.82f, 1.0f, -1.069f, 0.0f, 0.358f, 0.826f, 1.0f, -1.066f, 0.0f, 0.36f, 0.831f, 1.0f, -1.063f, 0.0f, 0.363f, 0.837f, 1.0f,
+ -1.059f, 0.0f, 0.366f, 0.842f, 1.0f, -1.055f, 0.0f, 0.368f, 0.847f, 1.0f, -1.051f, 0.0f, 0.371f, 0.851f, 1.0f, -1.047f, 0.0f, 0.373f, 0.856f, 1.0f,
+ -1.042f, 0.0f, 0.375f, 0.86f, 1.0f, -1.037f, 0.0f, 0.378f, 0.863f, 1.0f, -1.031f, 0.0f, 0.38f, 0.866f, 1.0f, -1.026f, 0.0f, 0.382f, 0.869f, 1.0f,
+ -1.02f, 0.0f, 0.384f, 0.871f, 1.0f, -1.014f, 0.0f, 0.386f, 0.873f, 1.0f, -1.007f, 0.0f, 0.387f, 0.875f, 1.0f, -1.0f, 0.0f, 0.389f, 0.876f, 1.0f,
+ -0.994f, 0.0f, 0.39f, 0.877f, 1.0f, -0.987f, 0.0f, 0.392f, 0.878f, 1.0f, -0.979f, 0.0f, 0.393f, 0.879f, 1.0f, -0.972f, 0.0f, 0.394f, 0.88f, 1.0f,
+ -0.964f, 0.0f, 0.395f, 0.881f, 1.0f, -0.956f, 0.0f, 0.395f, 0.881f, 1.0f, -0.948f, 0.0f, 0.395f, 0.882f, 1.0f, -0.94f, 0.0f, 0.395f, 0.882f, 1.0f,
+ -0.932f, 0.0f, 0.395f, 0.883f, 1.0f, -0.923f, 0.0f, 0.394f, 0.883f, 1.0f, -0.915f, 0.0f, 0.393f, 0.883f, 1.0f, -0.906f, 0.0f, 0.391f, 0.883f, 1.0f,
+ -0.896f, 0.0f, 0.389f, 0.881f, 1.0f, -0.887f, 0.0f, 0.386f, 0.876f, 1.0f, -0.877f, 0.0f, 0.382f, 0.866f, 1.0f, -0.867f, 0.0f, 0.378f, 0.85f, 1.0f,
+ -0.857f, 0.0f, 0.373f, 0.828f, 1.0f, -0.848f, 0.0f, 0.368f, 0.799f, 1.0f, -0.838f, 0.0f, 0.363f, 0.764f, 1.0f, -0.829f, 0.0f, 0.357f, 0.723f, 1.0f,
+ -0.819f, 0.0f, 0.352f, 0.679f, 1.0f, -0.811f, 0.0f, 0.347f, 0.631f, 1.0f, -0.802f, 0.0f, 0.342f, 0.579f, 1.0f, -0.794f, 0.0f, 0.338f, 0.525f, 1.0f,
+ -0.786f, 0.0f, 0.333f, 0.469f, 1.0f, -0.779f, 0.0f, 0.329f, 0.412f, 1.0f, -0.772f, 0.0f, 0.325f, 0.351f, 1.0f, -0.766f, 0.0f, 0.321f, 0.3f, 1.0f,
+ -0.757f, 0.0f, 0.317f, 0.219f, 1.0f,
+};
+
+static const float data29[205 * GP_PRIM_DATABUF_SIZE] = {
+ 0.816f, 0.0f, 0.326f, 0.285f, 1.0f, 0.819f, 0.0f, 0.328f, 0.287f, 1.0f, 0.821f, 0.0f, 0.33f, 0.29f, 1.0f, 0.823f, 0.0f, 0.331f, 0.295f, 1.0f,
+ 0.825f, 0.0f, 0.333f, 0.304f, 1.0f, 0.828f, 0.0f, 0.335f, 0.315f, 1.0f, 0.83f, 0.0f, 0.337f, 0.328f, 1.0f, 0.833f, 0.0f, 0.339f, 0.341f, 1.0f,
+ 0.836f, 0.0f, 0.341f, 0.355f, 1.0f, 0.839f, 0.0f, 0.343f, 0.368f, 1.0f, 0.842f, 0.0f, 0.345f, 0.38f, 1.0f, 0.845f, 0.0f, 0.347f, 0.392f, 1.0f,
+ 0.848f, 0.0f, 0.349f, 0.402f, 1.0f, 0.851f, 0.0f, 0.351f, 0.412f, 1.0f, 0.854f, 0.0f, 0.352f, 0.421f, 1.0f, 0.857f, 0.0f, 0.354f, 0.429f, 1.0f,
+ 0.861f, 0.0f, 0.356f, 0.437f, 1.0f, 0.865f, 0.0f, 0.357f, 0.444f, 1.0f, 0.869f, 0.0f, 0.359f, 0.452f, 1.0f, 0.872f, 0.0f, 0.36f, 0.46f, 1.0f,
+ 0.876f, 0.0f, 0.361f, 0.47f, 1.0f, 0.881f, 0.0f, 0.363f, 0.481f, 1.0f, 0.885f, 0.0f, 0.364f, 0.491f, 1.0f, 0.889f, 0.0f, 0.365f, 0.501f, 1.0f,
+ 0.893f, 0.0f, 0.366f, 0.511f, 1.0f, 0.898f, 0.0f, 0.367f, 0.52f, 1.0f, 0.902f, 0.0f, 0.368f, 0.528f, 1.0f, 0.906f, 0.0f, 0.37f, 0.535f, 1.0f,
+ 0.911f, 0.0f, 0.371f, 0.542f, 1.0f, 0.915f, 0.0f, 0.372f, 0.548f, 1.0f, 0.92f, 0.0f, 0.373f, 0.554f, 1.0f, 0.924f, 0.0f, 0.374f, 0.559f, 1.0f,
+ 0.929f, 0.0f, 0.375f, 0.564f, 1.0f, 0.933f, 0.0f, 0.376f, 0.567f, 1.0f, 0.938f, 0.0f, 0.377f, 0.57f, 1.0f, 0.943f, 0.0f, 0.378f, 0.572f, 1.0f,
+ 0.947f, 0.0f, 0.378f, 0.574f, 1.0f, 0.952f, 0.0f, 0.379f, 0.576f, 1.0f, 0.956f, 0.0f, 0.38f, 0.577f, 1.0f, 0.961f, 0.0f, 0.38f, 0.579f, 1.0f,
+ 0.966f, 0.0f, 0.381f, 0.581f, 1.0f, 0.971f, 0.0f, 0.381f, 0.585f, 1.0f, 0.975f, 0.0f, 0.382f, 0.588f, 1.0f, 0.98f, 0.0f, 0.382f, 0.591f, 1.0f,
+ 0.985f, 0.0f, 0.382f, 0.595f, 1.0f, 0.989f, 0.0f, 0.382f, 0.597f, 1.0f, 0.994f, 0.0f, 0.382f, 0.6f, 1.0f, 0.999f, 0.0f, 0.382f, 0.603f, 1.0f,
+ 1.003f, 0.0f, 0.382f, 0.605f, 1.0f, 1.008f, 0.0f, 0.381f, 0.607f, 1.0f, 1.013f, 0.0f, 0.381f, 0.61f, 1.0f, 1.017f, 0.0f, 0.381f, 0.611f, 1.0f,
+ 1.021f, 0.0f, 0.381f, 0.613f, 1.0f, 1.025f, 0.0f, 0.38f, 0.613f, 1.0f, 1.029f, 0.0f, 0.38f, 0.614f, 1.0f, 1.033f, 0.0f, 0.379f, 0.614f, 1.0f,
+ 1.037f, 0.0f, 0.379f, 0.614f, 1.0f, 1.041f, 0.0f, 0.378f, 0.614f, 1.0f, 1.044f, 0.0f, 0.378f, 0.614f, 1.0f, 1.048f, 0.0f, 0.377f, 0.614f, 1.0f,
+ 1.051f, 0.0f, 0.376f, 0.613f, 1.0f, 1.054f, 0.0f, 0.375f, 0.612f, 1.0f, 1.057f, 0.0f, 0.374f, 0.611f, 1.0f, 1.06f, 0.0f, 0.373f, 0.61f, 1.0f,
+ 1.063f, 0.0f, 0.372f, 0.609f, 1.0f, 1.066f, 0.0f, 0.371f, 0.609f, 1.0f, 1.068f, 0.0f, 0.37f, 0.608f, 1.0f, 1.071f, 0.0f, 0.368f, 0.608f, 1.0f,
+ 1.073f, 0.0f, 0.367f, 0.608f, 1.0f, 1.076f, 0.0f, 0.365f, 0.608f, 1.0f, 1.078f, 0.0f, 0.364f, 0.607f, 1.0f, 1.081f, 0.0f, 0.362f, 0.607f, 1.0f,
+ 1.083f, 0.0f, 0.36f, 0.607f, 1.0f, 1.085f, 0.0f, 0.358f, 0.606f, 1.0f, 1.087f, 0.0f, 0.356f, 0.606f, 1.0f, 1.09f, 0.0f, 0.354f, 0.606f, 1.0f,
+ 1.092f, 0.0f, 0.352f, 0.606f, 1.0f, 1.094f, 0.0f, 0.35f, 0.606f, 1.0f, 1.096f, 0.0f, 0.348f, 0.606f, 1.0f, 1.097f, 0.0f, 0.346f, 0.606f, 1.0f,
+ 1.099f, 0.0f, 0.344f, 0.606f, 1.0f, 1.101f, 0.0f, 0.341f, 0.606f, 1.0f, 1.103f, 0.0f, 0.339f, 0.606f, 1.0f, 1.104f, 0.0f, 0.337f, 0.607f, 1.0f,
+ 1.106f, 0.0f, 0.335f, 0.607f, 1.0f, 1.108f, 0.0f, 0.332f, 0.607f, 1.0f, 1.109f, 0.0f, 0.33f, 0.608f, 1.0f, 1.111f, 0.0f, 0.327f, 0.608f, 1.0f,
+ 1.113f, 0.0f, 0.324f, 0.608f, 1.0f, 1.114f, 0.0f, 0.322f, 0.609f, 1.0f, 1.116f, 0.0f, 0.319f, 0.609f, 1.0f, 1.117f, 0.0f, 0.316f, 0.609f, 1.0f,
+ 1.118f, 0.0f, 0.313f, 0.609f, 1.0f, 1.12f, 0.0f, 0.31f, 0.609f, 1.0f, 1.121f, 0.0f, 0.307f, 0.609f, 1.0f, 1.123f, 0.0f, 0.304f, 0.608f, 1.0f,
+ 1.124f, 0.0f, 0.301f, 0.608f, 1.0f, 1.125f, 0.0f, 0.297f, 0.607f, 1.0f, 1.126f, 0.0f, 0.294f, 0.606f, 1.0f, 1.127f, 0.0f, 0.29f, 0.605f, 1.0f,
+ 1.129f, 0.0f, 0.287f, 0.603f, 1.0f, 1.13f, 0.0f, 0.283f, 0.601f, 1.0f, 1.131f, 0.0f, 0.279f, 0.599f, 1.0f, 1.132f, 0.0f, 0.276f, 0.597f, 1.0f,
+ 1.132f, 0.0f, 0.272f, 0.595f, 1.0f, 1.133f, 0.0f, 0.268f, 0.593f, 1.0f, 1.134f, 0.0f, 0.264f, 0.592f, 1.0f, 1.135f, 0.0f, 0.26f, 0.591f, 1.0f,
+ 1.135f, 0.0f, 0.256f, 0.59f, 1.0f, 1.136f, 0.0f, 0.252f, 0.589f, 1.0f, 1.136f, 0.0f, 0.248f, 0.588f, 1.0f, 1.137f, 0.0f, 0.244f, 0.587f, 1.0f,
+ 1.137f, 0.0f, 0.24f, 0.586f, 1.0f, 1.138f, 0.0f, 0.236f, 0.585f, 1.0f, 1.138f, 0.0f, 0.232f, 0.584f, 1.0f, 1.138f, 0.0f, 0.228f, 0.582f, 1.0f,
+ 1.138f, 0.0f, 0.224f, 0.581f, 1.0f, 1.138f, 0.0f, 0.22f, 0.579f, 1.0f, 1.138f, 0.0f, 0.216f, 0.578f, 1.0f, 1.138f, 0.0f, 0.212f, 0.576f, 1.0f,
+ 1.138f, 0.0f, 0.208f, 0.575f, 1.0f, 1.138f, 0.0f, 0.204f, 0.573f, 1.0f, 1.137f, 0.0f, 0.2f, 0.572f, 1.0f, 1.137f, 0.0f, 0.196f, 0.571f, 1.0f,
+ 1.137f, 0.0f, 0.192f, 0.569f, 1.0f, 1.136f, 0.0f, 0.188f, 0.568f, 1.0f, 1.136f, 0.0f, 0.184f, 0.567f, 1.0f, 1.135f, 0.0f, 0.18f, 0.566f, 1.0f,
+ 1.134f, 0.0f, 0.176f, 0.565f, 1.0f, 1.133f, 0.0f, 0.172f, 0.563f, 1.0f, 1.132f, 0.0f, 0.168f, 0.561f, 1.0f, 1.131f, 0.0f, 0.164f, 0.559f, 1.0f,
+ 1.13f, 0.0f, 0.16f, 0.556f, 1.0f, 1.129f, 0.0f, 0.156f, 0.552f, 1.0f, 1.128f, 0.0f, 0.152f, 0.548f, 1.0f, 1.127f, 0.0f, 0.148f, 0.543f, 1.0f,
+ 1.126f, 0.0f, 0.144f, 0.537f, 1.0f, 1.124f, 0.0f, 0.14f, 0.53f, 1.0f, 1.123f, 0.0f, 0.136f, 0.522f, 1.0f, 1.122f, 0.0f, 0.132f, 0.514f, 1.0f,
+ 1.12f, 0.0f, 0.128f, 0.505f, 1.0f, 1.118f, 0.0f, 0.123f, 0.495f, 1.0f, 1.117f, 0.0f, 0.119f, 0.486f, 1.0f, 1.115f, 0.0f, 0.115f, 0.476f, 1.0f,
+ 1.113f, 0.0f, 0.111f, 0.466f, 1.0f, 1.111f, 0.0f, 0.107f, 0.456f, 1.0f, 1.11f, 0.0f, 0.102f, 0.446f, 1.0f, 1.108f, 0.0f, 0.098f, 0.436f, 1.0f,
+ 1.105f, 0.0f, 0.094f, 0.425f, 1.0f, 1.103f, 0.0f, 0.09f, 0.414f, 1.0f, 1.101f, 0.0f, 0.085f, 0.402f, 1.0f, 1.099f, 0.0f, 0.081f, 0.389f, 1.0f,
+ 1.096f, 0.0f, 0.077f, 0.377f, 1.0f, 1.094f, 0.0f, 0.072f, 0.364f, 1.0f, 1.091f, 0.0f, 0.068f, 0.351f, 1.0f, 1.088f, 0.0f, 0.063f, 0.338f, 1.0f,
+ 1.085f, 0.0f, 0.059f, 0.325f, 1.0f, 1.082f, 0.0f, 0.054f, 0.313f, 1.0f, 1.079f, 0.0f, 0.05f, 0.301f, 1.0f, 1.075f, 0.0f, 0.045f, 0.29f, 1.0f,
+ 1.071f, 0.0f, 0.04f, 0.281f, 1.0f, 1.067f, 0.0f, 0.035f, 0.272f, 1.0f, 1.063f, 0.0f, 0.031f, 0.266f, 1.0f, 1.059f, 0.0f, 0.026f, 0.261f, 1.0f,
+ 1.054f, 0.0f, 0.021f, 0.258f, 1.0f, 1.049f, 0.0f, 0.016f, 0.257f, 1.0f, 1.043f, 0.0f, 0.011f, 0.259f, 1.0f, 1.037f, 0.0f, 0.006f, 0.264f, 1.0f,
+ 1.031f, 0.0f, 0.0f, 0.272f, 1.0f, 1.025f, 0.0f, -0.005f, 0.283f, 1.0f, 1.018f, 0.0f, -0.01f, 0.296f, 1.0f, 1.011f, 0.0f, -0.015f, 0.313f, 1.0f,
+ 1.003f, 0.0f, -0.021f, 0.33f, 1.0f, 0.996f, 0.0f, -0.026f, 0.348f, 1.0f, 0.988f, 0.0f, -0.032f, 0.365f, 1.0f, 0.979f, 0.0f, -0.038f, 0.379f, 1.0f,
+ 0.971f, 0.0f, -0.044f, 0.389f, 1.0f, 0.962f, 0.0f, -0.05f, 0.394f, 1.0f, 0.953f, 0.0f, -0.057f, 0.392f, 1.0f, 0.944f, 0.0f, -0.063f, 0.384f, 1.0f,
+ 0.934f, 0.0f, -0.069f, 0.368f, 1.0f, 0.924f, 0.0f, -0.075f, 0.347f, 1.0f, 0.914f, 0.0f, -0.081f, 0.32f, 1.0f, 0.903f, 0.0f, -0.087f, 0.289f, 1.0f,
+ 0.893f, 0.0f, -0.092f, 0.256f, 1.0f, 0.882f, 0.0f, -0.098f, 0.223f, 1.0f, 0.871f, 0.0f, -0.103f, 0.191f, 1.0f, 0.86f, 0.0f, -0.108f, 0.162f, 1.0f,
+ 0.849f, 0.0f, -0.112f, 0.136f, 1.0f, 0.838f, 0.0f, -0.117f, 0.112f, 1.0f, 0.827f, 0.0f, -0.121f, 0.091f, 1.0f, 0.815f, 0.0f, -0.125f, 0.074f, 1.0f,
+ 0.804f, 0.0f, -0.128f, 0.059f, 1.0f, 0.793f, 0.0f, -0.132f, 0.046f, 1.0f, 0.782f, 0.0f, -0.135f, 0.036f, 1.0f, 0.771f, 0.0f, -0.138f, 0.028f, 1.0f,
+ 0.76f, 0.0f, -0.141f, 0.021f, 1.0f, 0.749f, 0.0f, -0.144f, 0.016f, 1.0f, 0.738f, 0.0f, -0.147f, 0.012f, 1.0f, 0.728f, 0.0f, -0.149f, 0.009f, 1.0f,
+ 0.718f, 0.0f, -0.152f, 0.006f, 1.0f, 0.708f, 0.0f, -0.154f, 0.004f, 1.0f, 0.699f, 0.0f, -0.157f, 0.003f, 1.0f, 0.691f, 0.0f, -0.159f, 0.002f, 1.0f,
+ 0.68f, 0.0f, -0.162f, 0.0f, 1.0f,
+};
+
+static const float data30[33 * GP_PRIM_DATABUF_SIZE] = {
+ -1.02f, 0.0f, 0.179f, 0.21f, 1.0f, -1.014f, 0.0f, 0.182f, 0.301f, 1.0f, -1.01f, 0.0f, 0.184f, 0.36f, 1.0f, -1.004f, 0.0f, 0.186f, 0.426f, 1.0f,
+ -0.999f, 0.0f, 0.188f, 0.479f, 1.0f, -0.993f, 0.0f, 0.19f, 0.519f, 1.0f, -0.987f, 0.0f, 0.191f, 0.545f, 1.0f, -0.981f, 0.0f, 0.192f, 0.562f, 1.0f,
+ -0.975f, 0.0f, 0.193f, 0.575f, 1.0f, -0.968f, 0.0f, 0.193f, 0.582f, 1.0f, -0.961f, 0.0f, 0.193f, 0.587f, 1.0f, -0.954f, 0.0f, 0.191f, 0.592f, 1.0f,
+ -0.946f, 0.0f, 0.19f, 0.597f, 1.0f, -0.938f, 0.0f, 0.187f, 0.6f, 1.0f, -0.93f, 0.0f, 0.183f, 0.603f, 1.0f, -0.922f, 0.0f, 0.178f, 0.606f, 1.0f,
+ -0.913f, 0.0f, 0.173f, 0.608f, 1.0f, -0.905f, 0.0f, 0.168f, 0.61f, 1.0f, -0.898f, 0.0f, 0.162f, 0.612f, 1.0f, -0.89f, 0.0f, 0.156f, 0.613f, 1.0f,
+ -0.883f, 0.0f, 0.15f, 0.612f, 1.0f, -0.877f, 0.0f, 0.143f, 0.608f, 1.0f, -0.871f, 0.0f, 0.137f, 0.602f, 1.0f, -0.865f, 0.0f, 0.131f, 0.593f, 1.0f,
+ -0.86f, 0.0f, 0.125f, 0.577f, 1.0f, -0.855f, 0.0f, 0.12f, 0.554f, 1.0f, -0.85f, 0.0f, 0.114f, 0.524f, 1.0f, -0.846f, 0.0f, 0.109f, 0.487f, 1.0f,
+ -0.842f, 0.0f, 0.104f, 0.443f, 1.0f, -0.838f, 0.0f, 0.1f, 0.394f, 1.0f, -0.835f, 0.0f, 0.095f, 0.339f, 1.0f, -0.832f, 0.0f, 0.091f, 0.295f, 1.0f,
+ -0.828f, 0.0f, 0.086f, 0.227f, 1.0f,
+};
+
+static const float data31[37 * GP_PRIM_DATABUF_SIZE] = {
+ 0.777f, 0.0f, 0.096f, 0.278f, 1.0f, 0.779f, 0.0f, 0.1f, 0.307f, 1.0f, 0.781f, 0.0f, 0.103f, 0.326f, 1.0f, 0.782f, 0.0f, 0.106f, 0.349f, 1.0f,
+ 0.784f, 0.0f, 0.109f, 0.372f, 1.0f, 0.786f, 0.0f, 0.112f, 0.395f, 1.0f, 0.789f, 0.0f, 0.116f, 0.418f, 1.0f, 0.791f, 0.0f, 0.119f, 0.44f, 1.0f,
+ 0.794f, 0.0f, 0.123f, 0.462f, 1.0f, 0.798f, 0.0f, 0.127f, 0.484f, 1.0f, 0.801f, 0.0f, 0.13f, 0.504f, 1.0f, 0.806f, 0.0f, 0.134f, 0.522f, 1.0f,
+ 0.81f, 0.0f, 0.138f, 0.54f, 1.0f, 0.815f, 0.0f, 0.142f, 0.556f, 1.0f, 0.82f, 0.0f, 0.146f, 0.571f, 1.0f, 0.826f, 0.0f, 0.15f, 0.584f, 1.0f,
+ 0.832f, 0.0f, 0.154f, 0.596f, 1.0f, 0.839f, 0.0f, 0.159f, 0.607f, 1.0f, 0.846f, 0.0f, 0.163f, 0.616f, 1.0f, 0.854f, 0.0f, 0.166f, 0.623f, 1.0f,
+ 0.862f, 0.0f, 0.17f, 0.628f, 1.0f, 0.87f, 0.0f, 0.174f, 0.632f, 1.0f, 0.878f, 0.0f, 0.177f, 0.632f, 1.0f, 0.887f, 0.0f, 0.18f, 0.63f, 1.0f,
+ 0.895f, 0.0f, 0.183f, 0.623f, 1.0f, 0.903f, 0.0f, 0.186f, 0.611f, 1.0f, 0.912f, 0.0f, 0.188f, 0.592f, 1.0f, 0.92f, 0.0f, 0.19f, 0.567f, 1.0f,
+ 0.928f, 0.0f, 0.192f, 0.533f, 1.0f, 0.935f, 0.0f, 0.193f, 0.492f, 1.0f, 0.943f, 0.0f, 0.194f, 0.442f, 1.0f, 0.95f, 0.0f, 0.196f, 0.385f, 1.0f,
+ 0.957f, 0.0f, 0.197f, 0.321f, 1.0f, 0.963f, 0.0f, 0.197f, 0.253f, 1.0f, 0.97f, 0.0f, 0.198f, 0.175f, 1.0f, 0.975f, 0.0f, 0.199f, 0.107f, 1.0f,
+ 0.983f, 0.0f, 0.199f, 0.0f, 1.0f,
+};
+
+static const float data32[201 * GP_PRIM_DATABUF_SIZE] = {
+ -0.437f, 0.0f, 0.508f, 0.0f, 1.0f, -0.435f, 0.0f, 0.51f, 0.0f, 1.0f, -0.434f, 0.0f, 0.511f, 0.0f, 1.0f, -0.432f, 0.0f, 0.512f, 0.0f, 1.0f,
+ -0.43f, 0.0f, 0.513f, 0.0f, 1.0f, -0.428f, 0.0f, 0.514f, 0.001f, 1.0f, -0.426f, 0.0f, 0.515f, 0.002f, 1.0f, -0.424f, 0.0f, 0.517f, 0.004f, 1.0f,
+ -0.422f, 0.0f, 0.518f, 0.007f, 1.0f, -0.42f, 0.0f, 0.519f, 0.012f, 1.0f, -0.418f, 0.0f, 0.521f, 0.018f, 1.0f, -0.416f, 0.0f, 0.522f, 0.025f, 1.0f,
+ -0.414f, 0.0f, 0.523f, 0.034f, 1.0f, -0.411f, 0.0f, 0.525f, 0.043f, 1.0f, -0.409f, 0.0f, 0.526f, 0.053f, 1.0f, -0.407f, 0.0f, 0.528f, 0.063f, 1.0f,
+ -0.404f, 0.0f, 0.529f, 0.073f, 1.0f, -0.402f, 0.0f, 0.531f, 0.083f, 1.0f, -0.399f, 0.0f, 0.532f, 0.092f, 1.0f, -0.396f, 0.0f, 0.534f, 0.101f, 1.0f,
+ -0.394f, 0.0f, 0.535f, 0.11f, 1.0f, -0.391f, 0.0f, 0.536f, 0.118f, 1.0f, -0.388f, 0.0f, 0.538f, 0.126f, 1.0f, -0.386f, 0.0f, 0.539f, 0.133f, 1.0f,
+ -0.383f, 0.0f, 0.54f, 0.14f, 1.0f, -0.38f, 0.0f, 0.542f, 0.147f, 1.0f, -0.377f, 0.0f, 0.543f, 0.153f, 1.0f, -0.374f, 0.0f, 0.544f, 0.159f, 1.0f,
+ -0.37f, 0.0f, 0.545f, 0.166f, 1.0f, -0.367f, 0.0f, 0.546f, 0.172f, 1.0f, -0.364f, 0.0f, 0.547f, 0.179f, 1.0f, -0.361f, 0.0f, 0.548f, 0.186f, 1.0f,
+ -0.357f, 0.0f, 0.549f, 0.193f, 1.0f, -0.354f, 0.0f, 0.55f, 0.202f, 1.0f, -0.35f, 0.0f, 0.551f, 0.211f, 1.0f, -0.347f, 0.0f, 0.552f, 0.221f, 1.0f,
+ -0.343f, 0.0f, 0.552f, 0.233f, 1.0f, -0.339f, 0.0f, 0.553f, 0.245f, 1.0f, -0.336f, 0.0f, 0.553f, 0.258f, 1.0f, -0.332f, 0.0f, 0.554f, 0.272f, 1.0f,
+ -0.328f, 0.0f, 0.554f, 0.286f, 1.0f, -0.324f, 0.0f, 0.554f, 0.301f, 1.0f, -0.321f, 0.0f, 0.555f, 0.317f, 1.0f, -0.317f, 0.0f, 0.555f, 0.332f, 1.0f,
+ -0.313f, 0.0f, 0.555f, 0.348f, 1.0f, -0.309f, 0.0f, 0.555f, 0.364f, 1.0f, -0.305f, 0.0f, 0.555f, 0.38f, 1.0f, -0.302f, 0.0f, 0.555f, 0.396f, 1.0f,
+ -0.298f, 0.0f, 0.555f, 0.411f, 1.0f, -0.294f, 0.0f, 0.555f, 0.426f, 1.0f, -0.29f, 0.0f, 0.554f, 0.44f, 1.0f, -0.287f, 0.0f, 0.554f, 0.454f, 1.0f,
+ -0.283f, 0.0f, 0.554f, 0.467f, 1.0f, -0.28f, 0.0f, 0.553f, 0.479f, 1.0f, -0.276f, 0.0f, 0.553f, 0.49f, 1.0f, -0.273f, 0.0f, 0.552f, 0.5f, 1.0f,
+ -0.269f, 0.0f, 0.552f, 0.51f, 1.0f, -0.266f, 0.0f, 0.551f, 0.519f, 1.0f, -0.263f, 0.0f, 0.55f, 0.527f, 1.0f, -0.26f, 0.0f, 0.549f, 0.534f, 1.0f,
+ -0.256f, 0.0f, 0.549f, 0.541f, 1.0f, -0.253f, 0.0f, 0.548f, 0.547f, 1.0f, -0.25f, 0.0f, 0.547f, 0.552f, 1.0f, -0.247f, 0.0f, 0.546f, 0.557f, 1.0f,
+ -0.244f, 0.0f, 0.545f, 0.561f, 1.0f, -0.241f, 0.0f, 0.544f, 0.564f, 1.0f, -0.238f, 0.0f, 0.543f, 0.567f, 1.0f, -0.235f, 0.0f, 0.542f, 0.57f, 1.0f,
+ -0.233f, 0.0f, 0.541f, 0.572f, 1.0f, -0.23f, 0.0f, 0.54f, 0.574f, 1.0f, -0.227f, 0.0f, 0.539f, 0.575f, 1.0f, -0.224f, 0.0f, 0.538f, 0.576f, 1.0f,
+ -0.221f, 0.0f, 0.537f, 0.577f, 1.0f, -0.219f, 0.0f, 0.535f, 0.578f, 1.0f, -0.216f, 0.0f, 0.534f, 0.578f, 1.0f, -0.213f, 0.0f, 0.533f, 0.579f, 1.0f,
+ -0.211f, 0.0f, 0.532f, 0.579f, 1.0f, -0.208f, 0.0f, 0.53f, 0.579f, 1.0f, -0.206f, 0.0f, 0.529f, 0.578f, 1.0f, -0.203f, 0.0f, 0.528f, 0.578f, 1.0f,
+ -0.2f, 0.0f, 0.526f, 0.577f, 1.0f, -0.198f, 0.0f, 0.525f, 0.576f, 1.0f, -0.195f, 0.0f, 0.523f, 0.575f, 1.0f, -0.193f, 0.0f, 0.522f, 0.574f, 1.0f,
+ -0.19f, 0.0f, 0.52f, 0.572f, 1.0f, -0.188f, 0.0f, 0.518f, 0.571f, 1.0f, -0.185f, 0.0f, 0.517f, 0.569f, 1.0f, -0.182f, 0.0f, 0.515f, 0.568f, 1.0f,
+ -0.18f, 0.0f, 0.513f, 0.567f, 1.0f, -0.177f, 0.0f, 0.512f, 0.565f, 1.0f, -0.174f, 0.0f, 0.51f, 0.564f, 1.0f, -0.172f, 0.0f, 0.508f, 0.562f, 1.0f,
+ -0.169f, 0.0f, 0.506f, 0.56f, 1.0f, -0.166f, 0.0f, 0.504f, 0.559f, 1.0f, -0.164f, 0.0f, 0.502f, 0.556f, 1.0f, -0.161f, 0.0f, 0.501f, 0.554f, 1.0f,
+ -0.158f, 0.0f, 0.499f, 0.552f, 1.0f, -0.155f, 0.0f, 0.497f, 0.55f, 1.0f, -0.153f, 0.0f, 0.495f, 0.547f, 1.0f, -0.15f, 0.0f, 0.493f, 0.545f, 1.0f,
+ -0.147f, 0.0f, 0.491f, 0.543f, 1.0f, -0.144f, 0.0f, 0.489f, 0.54f, 1.0f, -0.142f, 0.0f, 0.487f, 0.538f, 1.0f, -0.139f, 0.0f, 0.485f, 0.536f, 1.0f,
+ -0.136f, 0.0f, 0.483f, 0.533f, 1.0f, -0.133f, 0.0f, 0.481f, 0.53f, 1.0f, -0.13f, 0.0f, 0.479f, 0.527f, 1.0f, -0.127f, 0.0f, 0.477f, 0.524f, 1.0f,
+ -0.124f, 0.0f, 0.475f, 0.521f, 1.0f, -0.121f, 0.0f, 0.473f, 0.519f, 1.0f, -0.118f, 0.0f, 0.471f, 0.516f, 1.0f, -0.115f, 0.0f, 0.469f, 0.514f, 1.0f,
+ -0.112f, 0.0f, 0.467f, 0.511f, 1.0f, -0.109f, 0.0f, 0.465f, 0.509f, 1.0f, -0.106f, 0.0f, 0.463f, 0.506f, 1.0f, -0.103f, 0.0f, 0.461f, 0.503f, 1.0f,
+ -0.099f, 0.0f, 0.458f, 0.501f, 1.0f, -0.096f, 0.0f, 0.456f, 0.5f, 1.0f, -0.093f, 0.0f, 0.454f, 0.498f, 1.0f, -0.09f, 0.0f, 0.452f, 0.497f, 1.0f,
+ -0.086f, 0.0f, 0.45f, 0.496f, 1.0f, -0.083f, 0.0f, 0.448f, 0.496f, 1.0f, -0.079f, 0.0f, 0.446f, 0.495f, 1.0f, -0.076f, 0.0f, 0.444f, 0.495f, 1.0f,
+ -0.072f, 0.0f, 0.442f, 0.494f, 1.0f, -0.069f, 0.0f, 0.44f, 0.494f, 1.0f, -0.065f, 0.0f, 0.438f, 0.494f, 1.0f, -0.062f, 0.0f, 0.436f, 0.494f, 1.0f,
+ -0.058f, 0.0f, 0.435f, 0.494f, 1.0f, -0.054f, 0.0f, 0.433f, 0.494f, 1.0f, -0.05f, 0.0f, 0.431f, 0.494f, 1.0f, -0.046f, 0.0f, 0.43f, 0.494f, 1.0f,
+ -0.042f, 0.0f, 0.428f, 0.494f, 1.0f, -0.038f, 0.0f, 0.427f, 0.494f, 1.0f, -0.033f, 0.0f, 0.426f, 0.494f, 1.0f, -0.029f, 0.0f, 0.425f, 0.494f, 1.0f,
+ -0.025f, 0.0f, 0.424f, 0.494f, 1.0f, -0.02f, 0.0f, 0.423f, 0.494f, 1.0f, -0.015f, 0.0f, 0.422f, 0.494f, 1.0f, -0.011f, 0.0f, 0.422f, 0.494f, 1.0f,
+ -0.006f, 0.0f, 0.421f, 0.494f, 1.0f, -0.001f, 0.0f, 0.421f, 0.495f, 1.0f, 0.004f, 0.0f, 0.421f, 0.495f, 1.0f, 0.009f, 0.0f, 0.421f, 0.495f, 1.0f,
+ 0.014f, 0.0f, 0.422f, 0.495f, 1.0f, 0.019f, 0.0f, 0.422f, 0.495f, 1.0f, 0.024f, 0.0f, 0.423f, 0.495f, 1.0f, 0.029f, 0.0f, 0.424f, 0.495f, 1.0f,
+ 0.034f, 0.0f, 0.426f, 0.495f, 1.0f, 0.039f, 0.0f, 0.427f, 0.495f, 1.0f, 0.044f, 0.0f, 0.429f, 0.496f, 1.0f, 0.049f, 0.0f, 0.43f, 0.497f, 1.0f,
+ 0.054f, 0.0f, 0.432f, 0.498f, 1.0f, 0.059f, 0.0f, 0.435f, 0.5f, 1.0f, 0.064f, 0.0f, 0.438f, 0.502f, 1.0f, 0.069f, 0.0f, 0.44f, 0.506f, 1.0f,
+ 0.074f, 0.0f, 0.443f, 0.51f, 1.0f, 0.08f, 0.0f, 0.446f, 0.516f, 1.0f, 0.085f, 0.0f, 0.45f, 0.522f, 1.0f, 0.09f, 0.0f, 0.453f, 0.528f, 1.0f,
+ 0.095f, 0.0f, 0.456f, 0.533f, 1.0f, 0.101f, 0.0f, 0.46f, 0.537f, 1.0f, 0.107f, 0.0f, 0.463f, 0.539f, 1.0f, 0.112f, 0.0f, 0.467f, 0.542f, 1.0f,
+ 0.118f, 0.0f, 0.471f, 0.543f, 1.0f, 0.124f, 0.0f, 0.475f, 0.545f, 1.0f, 0.13f, 0.0f, 0.478f, 0.546f, 1.0f, 0.137f, 0.0f, 0.482f, 0.546f, 1.0f,
+ 0.143f, 0.0f, 0.486f, 0.547f, 1.0f, 0.149f, 0.0f, 0.49f, 0.546f, 1.0f, 0.156f, 0.0f, 0.493f, 0.544f, 1.0f, 0.163f, 0.0f, 0.497f, 0.54f, 1.0f,
+ 0.17f, 0.0f, 0.5f, 0.533f, 1.0f, 0.176f, 0.0f, 0.503f, 0.525f, 1.0f, 0.183f, 0.0f, 0.507f, 0.515f, 1.0f, 0.191f, 0.0f, 0.509f, 0.503f, 1.0f,
+ 0.198f, 0.0f, 0.512f, 0.491f, 1.0f, 0.205f, 0.0f, 0.515f, 0.477f, 1.0f, 0.214f, 0.0f, 0.518f, 0.462f, 1.0f, 0.222f, 0.0f, 0.521f, 0.445f, 1.0f,
+ 0.23f, 0.0f, 0.524f, 0.427f, 1.0f, 0.238f, 0.0f, 0.527f, 0.409f, 1.0f, 0.245f, 0.0f, 0.529f, 0.388f, 1.0f, 0.254f, 0.0f, 0.531f, 0.366f, 1.0f,
+ 0.262f, 0.0f, 0.532f, 0.343f, 1.0f, 0.272f, 0.0f, 0.533f, 0.317f, 1.0f, 0.282f, 0.0f, 0.534f, 0.289f, 1.0f, 0.292f, 0.0f, 0.535f, 0.258f, 1.0f,
+ 0.301f, 0.0f, 0.535f, 0.224f, 1.0f, 0.311f, 0.0f, 0.536f, 0.189f, 1.0f, 0.32f, 0.0f, 0.536f, 0.153f, 1.0f, 0.328f, 0.0f, 0.536f, 0.117f, 1.0f,
+ 0.338f, 0.0f, 0.537f, 0.084f, 1.0f, 0.346f, 0.0f, 0.537f, 0.057f, 1.0f, 0.353f, 0.0f, 0.536f, 0.037f, 1.0f, 0.361f, 0.0f, 0.536f, 0.022f, 1.0f,
+ 0.37f, 0.0f, 0.537f, 0.013f, 1.0f, 0.376f, 0.0f, 0.536f, 0.007f, 1.0f, 0.384f, 0.0f, 0.536f, 0.004f, 1.0f, 0.39f, 0.0f, 0.536f, 0.002f, 1.0f,
+ 0.399f, 0.0f, 0.535f, 0.0f, 1.0f,
+};
+
+static const float data33[69 * GP_PRIM_DATABUF_SIZE] = {
+ -0.308f, 0.0f, 0.151f, 0.363f, 1.0f, -0.31f, 0.0f, 0.15f, 0.377f, 1.0f, -0.311f, 0.0f, 0.149f, 0.386f, 1.0f, -0.313f, 0.0f, 0.149f, 0.397f, 1.0f,
+ -0.314f, 0.0f, 0.149f, 0.408f, 1.0f, -0.316f, 0.0f, 0.148f, 0.42f, 1.0f, -0.318f, 0.0f, 0.148f, 0.431f, 1.0f, -0.32f, 0.0f, 0.148f, 0.443f, 1.0f,
+ -0.322f, 0.0f, 0.148f, 0.455f, 1.0f, -0.325f, 0.0f, 0.149f, 0.467f, 1.0f, -0.327f, 0.0f, 0.149f, 0.478f, 1.0f, -0.33f, 0.0f, 0.151f, 0.49f, 1.0f,
+ -0.333f, 0.0f, 0.152f, 0.501f, 1.0f, -0.336f, 0.0f, 0.154f, 0.512f, 1.0f, -0.34f, 0.0f, 0.157f, 0.522f, 1.0f, -0.343f, 0.0f, 0.161f, 0.533f, 1.0f,
+ -0.346f, 0.0f, 0.166f, 0.543f, 1.0f, -0.349f, 0.0f, 0.171f, 0.553f, 1.0f, -0.351f, 0.0f, 0.178f, 0.563f, 1.0f, -0.352f, 0.0f, 0.186f, 0.572f, 1.0f,
+ -0.353f, 0.0f, 0.193f, 0.582f, 1.0f, -0.352f, 0.0f, 0.2f, 0.591f, 1.0f, -0.351f, 0.0f, 0.206f, 0.6f, 1.0f, -0.349f, 0.0f, 0.211f, 0.608f, 1.0f,
+ -0.347f, 0.0f, 0.215f, 0.616f, 1.0f, -0.345f, 0.0f, 0.219f, 0.623f, 1.0f, -0.343f, 0.0f, 0.222f, 0.63f, 1.0f, -0.341f, 0.0f, 0.224f, 0.637f, 1.0f,
+ -0.339f, 0.0f, 0.226f, 0.642f, 1.0f, -0.337f, 0.0f, 0.228f, 0.647f, 1.0f, -0.335f, 0.0f, 0.229f, 0.652f, 1.0f, -0.333f, 0.0f, 0.23f, 0.656f, 1.0f,
+ -0.332f, 0.0f, 0.231f, 0.66f, 1.0f, -0.33f, 0.0f, 0.232f, 0.663f, 1.0f, -0.328f, 0.0f, 0.232f, 0.666f, 1.0f, -0.327f, 0.0f, 0.233f, 0.669f, 1.0f,
+ -0.325f, 0.0f, 0.233f, 0.672f, 1.0f, -0.324f, 0.0f, 0.234f, 0.676f, 1.0f, -0.322f, 0.0f, 0.234f, 0.679f, 1.0f, -0.321f, 0.0f, 0.234f, 0.682f, 1.0f,
+ -0.319f, 0.0f, 0.234f, 0.686f, 1.0f, -0.317f, 0.0f, 0.234f, 0.689f, 1.0f, -0.316f, 0.0f, 0.234f, 0.693f, 1.0f, -0.314f, 0.0f, 0.234f, 0.697f, 1.0f,
+ -0.312f, 0.0f, 0.233f, 0.701f, 1.0f, -0.31f, 0.0f, 0.232f, 0.705f, 1.0f, -0.307f, 0.0f, 0.231f, 0.709f, 1.0f, -0.305f, 0.0f, 0.23f, 0.713f, 1.0f,
+ -0.302f, 0.0f, 0.228f, 0.716f, 1.0f, -0.299f, 0.0f, 0.225f, 0.719f, 1.0f, -0.295f, 0.0f, 0.222f, 0.722f, 1.0f, -0.292f, 0.0f, 0.217f, 0.725f, 1.0f,
+ -0.289f, 0.0f, 0.21f, 0.727f, 1.0f, -0.287f, 0.0f, 0.202f, 0.728f, 1.0f, -0.285f, 0.0f, 0.194f, 0.729f, 1.0f, -0.286f, 0.0f, 0.185f, 0.729f, 1.0f,
+ -0.287f, 0.0f, 0.178f, 0.728f, 1.0f, -0.289f, 0.0f, 0.171f, 0.726f, 1.0f, -0.292f, 0.0f, 0.166f, 0.723f, 1.0f, -0.294f, 0.0f, 0.162f, 0.717f, 1.0f,
+ -0.297f, 0.0f, 0.159f, 0.71f, 1.0f, -0.299f, 0.0f, 0.157f, 0.701f, 1.0f, -0.301f, 0.0f, 0.155f, 0.689f, 1.0f, -0.303f, 0.0f, 0.154f, 0.675f, 1.0f,
+ -0.305f, 0.0f, 0.152f, 0.659f, 1.0f, -0.306f, 0.0f, 0.151f, 0.641f, 1.0f, -0.308f, 0.0f, 0.151f, 0.62f, 1.0f, -0.309f, 0.0f, 0.15f, 0.602f, 1.0f,
+ -0.31f, 0.0f, 0.15f, 0.572f, 1.0f,
+};
+
+static const float data34[57 * GP_PRIM_DATABUF_SIZE] = {
+ 0.302f, 0.0f, 0.166f, 0.25f, 1.0f, 0.301f, 0.0f, 0.167f, 0.319f, 1.0f, 0.3f, 0.0f, 0.167f, 0.363f, 1.0f, 0.299f, 0.0f, 0.167f, 0.414f, 1.0f,
+ 0.298f, 0.0f, 0.167f, 0.459f, 1.0f, 0.296f, 0.0f, 0.168f, 0.501f, 1.0f, 0.295f, 0.0f, 0.168f, 0.539f, 1.0f, 0.293f, 0.0f, 0.169f, 0.573f, 1.0f,
+ 0.291f, 0.0f, 0.17f, 0.603f, 1.0f, 0.289f, 0.0f, 0.171f, 0.629f, 1.0f, 0.286f, 0.0f, 0.173f, 0.652f, 1.0f, 0.283f, 0.0f, 0.176f, 0.672f, 1.0f,
+ 0.279f, 0.0f, 0.18f, 0.69f, 1.0f, 0.276f, 0.0f, 0.186f, 0.705f, 1.0f, 0.272f, 0.0f, 0.195f, 0.719f, 1.0f, 0.271f, 0.0f, 0.205f, 0.73f, 1.0f,
+ 0.272f, 0.0f, 0.217f, 0.741f, 1.0f, 0.275f, 0.0f, 0.227f, 0.75f, 1.0f, 0.279f, 0.0f, 0.234f, 0.758f, 1.0f, 0.283f, 0.0f, 0.24f, 0.765f, 1.0f,
+ 0.287f, 0.0f, 0.243f, 0.771f, 1.0f, 0.291f, 0.0f, 0.245f, 0.776f, 1.0f, 0.294f, 0.0f, 0.247f, 0.781f, 1.0f, 0.296f, 0.0f, 0.248f, 0.785f, 1.0f,
+ 0.299f, 0.0f, 0.249f, 0.789f, 1.0f, 0.301f, 0.0f, 0.249f, 0.793f, 1.0f, 0.303f, 0.0f, 0.249f, 0.796f, 1.0f, 0.305f, 0.0f, 0.25f, 0.799f, 1.0f,
+ 0.306f, 0.0f, 0.25f, 0.802f, 1.0f, 0.308f, 0.0f, 0.249f, 0.805f, 1.0f, 0.31f, 0.0f, 0.249f, 0.808f, 1.0f, 0.311f, 0.0f, 0.249f, 0.81f, 1.0f,
+ 0.313f, 0.0f, 0.249f, 0.813f, 1.0f, 0.314f, 0.0f, 0.248f, 0.816f, 1.0f, 0.316f, 0.0f, 0.248f, 0.819f, 1.0f, 0.317f, 0.0f, 0.247f, 0.822f, 1.0f,
+ 0.319f, 0.0f, 0.246f, 0.825f, 1.0f, 0.321f, 0.0f, 0.245f, 0.828f, 1.0f, 0.323f, 0.0f, 0.244f, 0.832f, 1.0f, 0.325f, 0.0f, 0.243f, 0.835f, 1.0f,
+ 0.328f, 0.0f, 0.24f, 0.838f, 1.0f, 0.33f, 0.0f, 0.237f, 0.841f, 1.0f, 0.333f, 0.0f, 0.233f, 0.844f, 1.0f, 0.337f, 0.0f, 0.228f, 0.847f, 1.0f,
+ 0.339f, 0.0f, 0.219f, 0.849f, 1.0f, 0.341f, 0.0f, 0.209f, 0.852f, 1.0f, 0.34f, 0.0f, 0.197f, 0.854f, 1.0f, 0.336f, 0.0f, 0.186f, 0.856f, 1.0f,
+ 0.331f, 0.0f, 0.178f, 0.858f, 1.0f, 0.325f, 0.0f, 0.173f, 0.86f, 1.0f, 0.321f, 0.0f, 0.17f, 0.861f, 1.0f, 0.318f, 0.0f, 0.169f, 0.862f, 1.0f,
+ 0.315f, 0.0f, 0.168f, 0.864f, 1.0f, 0.312f, 0.0f, 0.167f, 0.865f, 1.0f, 0.311f, 0.0f, 0.167f, 0.866f, 1.0f, 0.309f, 0.0f, 0.166f, 0.867f, 1.0f,
+ 0.308f, 0.0f, 0.166f, 0.868f, 1.0f,
+};
+
+static const float data35[261 * GP_PRIM_DATABUF_SIZE] = {
+ -0.685f, 0.0f, 0.408f, 0.0f, 1.0f, -0.683f, 0.0f, 0.41f, 0.023f, 1.0f, -0.681f, 0.0f, 0.412f, 0.051f, 1.0f, -0.679f, 0.0f, 0.414f, 0.092f, 1.0f,
+ -0.678f, 0.0f, 0.415f, 0.125f, 1.0f, -0.676f, 0.0f, 0.417f, 0.149f, 1.0f, -0.674f, 0.0f, 0.419f, 0.167f, 1.0f, -0.672f, 0.0f, 0.42f, 0.183f, 1.0f,
+ -0.67f, 0.0f, 0.422f, 0.199f, 1.0f, -0.668f, 0.0f, 0.424f, 0.218f, 1.0f, -0.666f, 0.0f, 0.426f, 0.237f, 1.0f, -0.664f, 0.0f, 0.429f, 0.257f, 1.0f,
+ -0.661f, 0.0f, 0.431f, 0.275f, 1.0f, -0.659f, 0.0f, 0.434f, 0.291f, 1.0f, -0.657f, 0.0f, 0.436f, 0.305f, 1.0f, -0.655f, 0.0f, 0.439f, 0.315f, 1.0f,
+ -0.653f, 0.0f, 0.442f, 0.322f, 1.0f, -0.65f, 0.0f, 0.444f, 0.327f, 1.0f, -0.648f, 0.0f, 0.447f, 0.331f, 1.0f, -0.646f, 0.0f, 0.45f, 0.334f, 1.0f,
+ -0.643f, 0.0f, 0.453f, 0.334f, 1.0f, -0.641f, 0.0f, 0.456f, 0.334f, 1.0f, -0.639f, 0.0f, 0.459f, 0.334f, 1.0f, -0.636f, 0.0f, 0.462f, 0.333f, 1.0f,
+ -0.634f, 0.0f, 0.466f, 0.332f, 1.0f, -0.631f, 0.0f, 0.469f, 0.332f, 1.0f, -0.628f, 0.0f, 0.473f, 0.332f, 1.0f, -0.625f, 0.0f, 0.476f, 0.333f, 1.0f,
+ -0.622f, 0.0f, 0.48f, 0.335f, 1.0f, -0.618f, 0.0f, 0.483f, 0.338f, 1.0f, -0.615f, 0.0f, 0.488f, 0.342f, 1.0f, -0.611f, 0.0f, 0.492f, 0.347f, 1.0f,
+ -0.608f, 0.0f, 0.495f, 0.352f, 1.0f, -0.605f, 0.0f, 0.5f, 0.358f, 1.0f, -0.601f, 0.0f, 0.505f, 0.363f, 1.0f, -0.597f, 0.0f, 0.509f, 0.366f, 1.0f,
+ -0.593f, 0.0f, 0.514f, 0.367f, 1.0f, -0.589f, 0.0f, 0.518f, 0.367f, 1.0f, -0.585f, 0.0f, 0.522f, 0.369f, 1.0f, -0.582f, 0.0f, 0.526f, 0.372f, 1.0f,
+ -0.578f, 0.0f, 0.531f, 0.376f, 1.0f, -0.575f, 0.0f, 0.535f, 0.382f, 1.0f, -0.571f, 0.0f, 0.539f, 0.388f, 1.0f, -0.567f, 0.0f, 0.543f, 0.394f, 1.0f,
+ -0.563f, 0.0f, 0.547f, 0.4f, 1.0f, -0.56f, 0.0f, 0.551f, 0.406f, 1.0f, -0.556f, 0.0f, 0.555f, 0.411f, 1.0f, -0.552f, 0.0f, 0.559f, 0.415f, 1.0f,
+ -0.548f, 0.0f, 0.563f, 0.418f, 1.0f, -0.544f, 0.0f, 0.566f, 0.419f, 1.0f, -0.54f, 0.0f, 0.569f, 0.42f, 1.0f, -0.537f, 0.0f, 0.572f, 0.421f, 1.0f,
+ -0.533f, 0.0f, 0.576f, 0.421f, 1.0f, -0.529f, 0.0f, 0.579f, 0.421f, 1.0f, -0.526f, 0.0f, 0.582f, 0.422f, 1.0f, -0.523f, 0.0f, 0.585f, 0.422f, 1.0f,
+ -0.52f, 0.0f, 0.588f, 0.423f, 1.0f, -0.516f, 0.0f, 0.591f, 0.426f, 1.0f, -0.513f, 0.0f, 0.594f, 0.43f, 1.0f, -0.51f, 0.0f, 0.597f, 0.435f, 1.0f,
+ -0.507f, 0.0f, 0.6f, 0.441f, 1.0f, -0.504f, 0.0f, 0.603f, 0.447f, 1.0f, -0.501f, 0.0f, 0.606f, 0.453f, 1.0f, -0.498f, 0.0f, 0.609f, 0.458f, 1.0f,
+ -0.496f, 0.0f, 0.611f, 0.461f, 1.0f, -0.493f, 0.0f, 0.614f, 0.465f, 1.0f, -0.49f, 0.0f, 0.616f, 0.468f, 1.0f, -0.487f, 0.0f, 0.619f, 0.472f, 1.0f,
+ -0.484f, 0.0f, 0.621f, 0.476f, 1.0f, -0.482f, 0.0f, 0.624f, 0.48f, 1.0f, -0.479f, 0.0f, 0.627f, 0.484f, 1.0f, -0.476f, 0.0f, 0.629f, 0.487f, 1.0f,
+ -0.473f, 0.0f, 0.632f, 0.491f, 1.0f, -0.471f, 0.0f, 0.634f, 0.495f, 1.0f, -0.468f, 0.0f, 0.637f, 0.499f, 1.0f, -0.465f, 0.0f, 0.639f, 0.504f, 1.0f,
+ -0.462f, 0.0f, 0.641f, 0.508f, 1.0f, -0.459f, 0.0f, 0.643f, 0.513f, 1.0f, -0.456f, 0.0f, 0.646f, 0.519f, 1.0f, -0.453f, 0.0f, 0.648f, 0.525f, 1.0f,
+ -0.45f, 0.0f, 0.65f, 0.533f, 1.0f, -0.447f, 0.0f, 0.652f, 0.54f, 1.0f, -0.444f, 0.0f, 0.655f, 0.546f, 1.0f, -0.441f, 0.0f, 0.657f, 0.553f, 1.0f,
+ -0.438f, 0.0f, 0.659f, 0.56f, 1.0f, -0.435f, 0.0f, 0.662f, 0.567f, 1.0f, -0.432f, 0.0f, 0.664f, 0.574f, 1.0f, -0.429f, 0.0f, 0.666f, 0.58f, 1.0f,
+ -0.426f, 0.0f, 0.669f, 0.585f, 1.0f, -0.423f, 0.0f, 0.671f, 0.591f, 1.0f, -0.419f, 0.0f, 0.673f, 0.595f, 1.0f, -0.416f, 0.0f, 0.675f, 0.6f, 1.0f,
+ -0.412f, 0.0f, 0.678f, 0.604f, 1.0f, -0.409f, 0.0f, 0.68f, 0.609f, 1.0f, -0.405f, 0.0f, 0.682f, 0.613f, 1.0f, -0.401f, 0.0f, 0.684f, 0.618f, 1.0f,
+ -0.398f, 0.0f, 0.687f, 0.622f, 1.0f, -0.394f, 0.0f, 0.689f, 0.627f, 1.0f, -0.39f, 0.0f, 0.692f, 0.632f, 1.0f, -0.386f, 0.0f, 0.694f, 0.638f, 1.0f,
+ -0.381f, 0.0f, 0.697f, 0.643f, 1.0f, -0.377f, 0.0f, 0.7f, 0.649f, 1.0f, -0.373f, 0.0f, 0.702f, 0.654f, 1.0f, -0.368f, 0.0f, 0.705f, 0.659f, 1.0f,
+ -0.363f, 0.0f, 0.707f, 0.663f, 1.0f, -0.359f, 0.0f, 0.71f, 0.667f, 1.0f, -0.354f, 0.0f, 0.712f, 0.671f, 1.0f, -0.349f, 0.0f, 0.715f, 0.674f, 1.0f,
+ -0.345f, 0.0f, 0.717f, 0.677f, 1.0f, -0.34f, 0.0f, 0.72f, 0.68f, 1.0f, -0.335f, 0.0f, 0.722f, 0.683f, 1.0f, -0.33f, 0.0f, 0.725f, 0.685f, 1.0f,
+ -0.326f, 0.0f, 0.727f, 0.687f, 1.0f, -0.321f, 0.0f, 0.73f, 0.689f, 1.0f, -0.316f, 0.0f, 0.732f, 0.691f, 1.0f, -0.312f, 0.0f, 0.734f, 0.693f, 1.0f,
+ -0.307f, 0.0f, 0.736f, 0.694f, 1.0f, -0.302f, 0.0f, 0.738f, 0.696f, 1.0f, -0.298f, 0.0f, 0.74f, 0.697f, 1.0f, -0.293f, 0.0f, 0.741f, 0.698f, 1.0f,
+ -0.288f, 0.0f, 0.743f, 0.699f, 1.0f, -0.284f, 0.0f, 0.745f, 0.699f, 1.0f, -0.279f, 0.0f, 0.746f, 0.7f, 1.0f, -0.275f, 0.0f, 0.748f, 0.701f, 1.0f,
+ -0.27f, 0.0f, 0.749f, 0.702f, 1.0f, -0.265f, 0.0f, 0.751f, 0.702f, 1.0f, -0.261f, 0.0f, 0.752f, 0.704f, 1.0f, -0.256f, 0.0f, 0.753f, 0.705f, 1.0f,
+ -0.252f, 0.0f, 0.755f, 0.706f, 1.0f, -0.247f, 0.0f, 0.756f, 0.707f, 1.0f, -0.242f, 0.0f, 0.757f, 0.709f, 1.0f, -0.237f, 0.0f, 0.758f, 0.711f, 1.0f,
+ -0.233f, 0.0f, 0.759f, 0.713f, 1.0f, -0.228f, 0.0f, 0.761f, 0.715f, 1.0f, -0.223f, 0.0f, 0.762f, 0.717f, 1.0f, -0.218f, 0.0f, 0.763f, 0.719f, 1.0f,
+ -0.213f, 0.0f, 0.764f, 0.721f, 1.0f, -0.209f, 0.0f, 0.765f, 0.723f, 1.0f, -0.204f, 0.0f, 0.765f, 0.726f, 1.0f, -0.199f, 0.0f, 0.766f, 0.728f, 1.0f,
+ -0.194f, 0.0f, 0.767f, 0.73f, 1.0f, -0.189f, 0.0f, 0.768f, 0.731f, 1.0f, -0.183f, 0.0f, 0.769f, 0.733f, 1.0f, -0.178f, 0.0f, 0.77f, 0.735f, 1.0f,
+ -0.173f, 0.0f, 0.77f, 0.736f, 1.0f, -0.168f, 0.0f, 0.771f, 0.738f, 1.0f, -0.163f, 0.0f, 0.772f, 0.739f, 1.0f, -0.158f, 0.0f, 0.772f, 0.741f, 1.0f,
+ -0.152f, 0.0f, 0.773f, 0.742f, 1.0f, -0.147f, 0.0f, 0.774f, 0.744f, 1.0f, -0.142f, 0.0f, 0.774f, 0.746f, 1.0f, -0.137f, 0.0f, 0.775f, 0.748f, 1.0f,
+ -0.132f, 0.0f, 0.775f, 0.749f, 1.0f, -0.127f, 0.0f, 0.776f, 0.751f, 1.0f, -0.122f, 0.0f, 0.776f, 0.752f, 1.0f, -0.117f, 0.0f, 0.776f, 0.753f, 1.0f,
+ -0.112f, 0.0f, 0.777f, 0.754f, 1.0f, -0.108f, 0.0f, 0.777f, 0.755f, 1.0f, -0.103f, 0.0f, 0.777f, 0.755f, 1.0f, -0.099f, 0.0f, 0.777f, 0.756f, 1.0f,
+ -0.095f, 0.0f, 0.778f, 0.757f, 1.0f, -0.09f, 0.0f, 0.778f, 0.758f, 1.0f, -0.086f, 0.0f, 0.778f, 0.759f, 1.0f, -0.082f, 0.0f, 0.778f, 0.759f, 1.0f,
+ -0.077f, 0.0f, 0.778f, 0.76f, 1.0f, -0.073f, 0.0f, 0.779f, 0.76f, 1.0f, -0.069f, 0.0f, 0.779f, 0.761f, 1.0f, -0.064f, 0.0f, 0.779f, 0.761f, 1.0f,
+ -0.06f, 0.0f, 0.779f, 0.761f, 1.0f, -0.055f, 0.0f, 0.78f, 0.762f, 1.0f, -0.051f, 0.0f, 0.78f, 0.762f, 1.0f, -0.046f, 0.0f, 0.78f, 0.762f, 1.0f,
+ -0.041f, 0.0f, 0.78f, 0.762f, 1.0f, -0.037f, 0.0f, 0.781f, 0.762f, 1.0f, -0.032f, 0.0f, 0.781f, 0.763f, 1.0f, -0.027f, 0.0f, 0.781f, 0.763f, 1.0f,
+ -0.022f, 0.0f, 0.781f, 0.763f, 1.0f, -0.017f, 0.0f, 0.781f, 0.764f, 1.0f, -0.012f, 0.0f, 0.782f, 0.764f, 1.0f, -0.006f, 0.0f, 0.782f, 0.764f, 1.0f,
+ -0.001f, 0.0f, 0.782f, 0.765f, 1.0f, 0.004f, 0.0f, 0.782f, 0.766f, 1.0f, 0.009f, 0.0f, 0.782f, 0.766f, 1.0f, 0.015f, 0.0f, 0.782f, 0.767f, 1.0f,
+ 0.02f, 0.0f, 0.782f, 0.768f, 1.0f, 0.025f, 0.0f, 0.782f, 0.769f, 1.0f, 0.031f, 0.0f, 0.782f, 0.77f, 1.0f, 0.036f, 0.0f, 0.782f, 0.771f, 1.0f,
+ 0.042f, 0.0f, 0.782f, 0.772f, 1.0f, 0.048f, 0.0f, 0.782f, 0.773f, 1.0f, 0.053f, 0.0f, 0.782f, 0.774f, 1.0f, 0.059f, 0.0f, 0.782f, 0.775f, 1.0f,
+ 0.065f, 0.0f, 0.782f, 0.775f, 1.0f, 0.07f, 0.0f, 0.782f, 0.776f, 1.0f, 0.076f, 0.0f, 0.782f, 0.776f, 1.0f, 0.082f, 0.0f, 0.782f, 0.776f, 1.0f,
+ 0.088f, 0.0f, 0.782f, 0.776f, 1.0f, 0.094f, 0.0f, 0.782f, 0.777f, 1.0f, 0.1f, 0.0f, 0.781f, 0.777f, 1.0f, 0.106f, 0.0f, 0.781f, 0.778f, 1.0f,
+ 0.111f, 0.0f, 0.781f, 0.779f, 1.0f, 0.117f, 0.0f, 0.781f, 0.779f, 1.0f, 0.123f, 0.0f, 0.781f, 0.78f, 1.0f, 0.129f, 0.0f, 0.78f, 0.78f, 1.0f,
+ 0.135f, 0.0f, 0.78f, 0.781f, 1.0f, 0.141f, 0.0f, 0.779f, 0.781f, 1.0f, 0.147f, 0.0f, 0.779f, 0.782f, 1.0f, 0.153f, 0.0f, 0.778f, 0.783f, 1.0f,
+ 0.159f, 0.0f, 0.777f, 0.784f, 1.0f, 0.165f, 0.0f, 0.776f, 0.785f, 1.0f, 0.171f, 0.0f, 0.775f, 0.786f, 1.0f, 0.178f, 0.0f, 0.774f, 0.787f, 1.0f,
+ 0.185f, 0.0f, 0.773f, 0.788f, 1.0f, 0.192f, 0.0f, 0.772f, 0.789f, 1.0f, 0.2f, 0.0f, 0.771f, 0.79f, 1.0f, 0.208f, 0.0f, 0.77f, 0.791f, 1.0f,
+ 0.218f, 0.0f, 0.768f, 0.793f, 1.0f, 0.228f, 0.0f, 0.766f, 0.796f, 1.0f, 0.239f, 0.0f, 0.764f, 0.799f, 1.0f, 0.25f, 0.0f, 0.762f, 0.802f, 1.0f,
+ 0.261f, 0.0f, 0.759f, 0.806f, 1.0f, 0.271f, 0.0f, 0.755f, 0.81f, 1.0f, 0.282f, 0.0f, 0.752f, 0.815f, 1.0f, 0.293f, 0.0f, 0.748f, 0.819f, 1.0f,
+ 0.304f, 0.0f, 0.744f, 0.825f, 1.0f, 0.315f, 0.0f, 0.74f, 0.83f, 1.0f, 0.326f, 0.0f, 0.736f, 0.836f, 1.0f, 0.337f, 0.0f, 0.731f, 0.843f, 1.0f,
+ 0.349f, 0.0f, 0.727f, 0.85f, 1.0f, 0.361f, 0.0f, 0.722f, 0.858f, 1.0f, 0.372f, 0.0f, 0.718f, 0.866f, 1.0f, 0.384f, 0.0f, 0.712f, 0.874f, 1.0f,
+ 0.395f, 0.0f, 0.706f, 0.882f, 1.0f, 0.407f, 0.0f, 0.7f, 0.89f, 1.0f, 0.418f, 0.0f, 0.693f, 0.898f, 1.0f, 0.43f, 0.0f, 0.685f, 0.905f, 1.0f,
+ 0.442f, 0.0f, 0.677f, 0.912f, 1.0f, 0.458f, 0.0f, 0.666f, 0.918f, 1.0f, 0.473f, 0.0f, 0.654f, 0.924f, 1.0f, 0.49f, 0.0f, 0.64f, 0.93f, 1.0f,
+ 0.506f, 0.0f, 0.625f, 0.935f, 1.0f, 0.522f, 0.0f, 0.611f, 0.939f, 1.0f, 0.538f, 0.0f, 0.596f, 0.941f, 1.0f, 0.554f, 0.0f, 0.58f, 0.942f, 1.0f,
+ 0.569f, 0.0f, 0.564f, 0.941f, 1.0f, 0.584f, 0.0f, 0.548f, 0.935f, 1.0f, 0.598f, 0.0f, 0.533f, 0.925f, 1.0f, 0.612f, 0.0f, 0.517f, 0.91f, 1.0f,
+ 0.625f, 0.0f, 0.501f, 0.891f, 1.0f, 0.638f, 0.0f, 0.484f, 0.868f, 1.0f, 0.65f, 0.0f, 0.468f, 0.839f, 1.0f, 0.662f, 0.0f, 0.452f, 0.806f, 1.0f,
+ 0.671f, 0.0f, 0.437f, 0.766f, 1.0f, 0.679f, 0.0f, 0.423f, 0.718f, 1.0f, 0.685f, 0.0f, 0.412f, 0.661f, 1.0f, 0.691f, 0.0f, 0.403f, 0.595f, 1.0f,
+ 0.697f, 0.0f, 0.396f, 0.519f, 1.0f, 0.701f, 0.0f, 0.391f, 0.44f, 1.0f, 0.704f, 0.0f, 0.387f, 0.344f, 1.0f, 0.707f, 0.0f, 0.384f, 0.264f, 1.0f,
+ 0.711f, 0.0f, 0.38f, 0.133f, 1.0f,
+};
+
+/* ***************************************************************** */
+/* Monkey Color Data */
+
+static const ColorTemplate gp_monkey_pct_black = {
+ "Black",
+ {0.0f, 0.0f, 0.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
+};
+
+static const ColorTemplate gp_monkey_pct_skin = {
+ "Skin",
+ {0.553f, 0.39f, 0.266f, 0.0f},
+ {0.733f, 0.567f, 0.359f, 1.0f},
+};
+
+static const ColorTemplate gp_monkey_pct_skin_light = {
+ "Skin_Light",
+ {0.553f, 0.39f, 0.266f, 0.0f},
+ {0.913f, 0.828f, 0.637f, 1.0f},
+};
+
+static const ColorTemplate gp_monkey_pct_skin_shadow = {
+ "Skin_Shadow",
+ {0.553f, 0.39f, 0.266f, 0.0f},
+ {0.32f, 0.29f, 0.223f, 1.0f},
+};
+
+static const ColorTemplate gp_monkey_pct_eyes = {
+ "Eyes",
+ {0.553f, 0.39f, 0.266f, 0.0f},
+ {0.773f, 0.762f, 0.73f, 1.0f},
+};
+
+static const ColorTemplate gp_monkey_pct_pupils = {
+ "Pupils",
+ {0.107f, 0.075f, 0.051f, 0.0f},
+ {0.153f, 0.057f, 0.063f, 1.0f},
+};
+
+/* ***************************************************************** */
+/* Monkey API */
+
+/* add a 2D Suzanne (original model created by Matias Mendiola) */
+void ED_gpencil_create_monkey(bContext *C, float mat[4][4])
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDstroke *gps;
+
+ /* create colors */
+ int color_Black = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_black);
+ int color_Skin = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin);
+ int color_Skin_Light = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin_light);
+ int color_Skin_Shadow = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin_shadow);
+ int color_Eyes = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_eyes);
+ int color_Pupils = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_pupils);
+
+ /* layers */
+ /* NOTE: For now, we just add new layers, to make it easier to separate out old/new instances */
+ bGPDlayer *Colors = BKE_gpencil_layer_addnew(gpd, "Colors", false);
+ bGPDlayer *Lines = BKE_gpencil_layer_addnew(gpd, "Lines", true);
+
+ /* frames */
+ /* NOTE: No need to check for existing, as this will tkae care of it for us */
+ bGPDframe *frameColor = BKE_gpencil_frame_addnew(Colors, cfra_eval);
+ bGPDframe *frameLines = BKE_gpencil_frame_addnew(Lines, cfra_eval);
+
+ /* generate strokes */
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin, 538, 3);
+ BKE_gpencil_stroke_add_points(gps, data0, 538, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Eyes, 136, 3);
+ BKE_gpencil_stroke_add_points(gps, data1, 136, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin, 2, 3);
+ BKE_gpencil_stroke_add_points(gps, data2, 2, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 1, 3);
+ BKE_gpencil_stroke_add_points(gps, data3, 1, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 1, 3);
+ BKE_gpencil_stroke_add_points(gps, data4, 1, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 48, 3);
+ BKE_gpencil_stroke_add_points(gps, data5, 48, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 47, 3);
+ BKE_gpencil_stroke_add_points(gps, data6, 47, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 162, 3);
+ BKE_gpencil_stroke_add_points(gps, data7, 162, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 55, 3);
+ BKE_gpencil_stroke_add_points(gps, data8, 55, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 70, 3);
+ BKE_gpencil_stroke_add_points(gps, data9, 70, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 227, 3);
+ BKE_gpencil_stroke_add_points(gps, data10, 227, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 1, 3);
+ BKE_gpencil_stroke_add_points(gps, data11, 1, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 123, 3);
+ BKE_gpencil_stroke_add_points(gps, data12, 123, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 125, 3);
+ BKE_gpencil_stroke_add_points(gps, data13, 125, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 45, 3);
+ BKE_gpencil_stroke_add_points(gps, data14, 45, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 44, 3);
+ BKE_gpencil_stroke_add_points(gps, data15, 44, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 84, 3);
+ BKE_gpencil_stroke_add_points(gps, data16, 84, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 56, 3);
+ BKE_gpencil_stroke_add_points(gps, data17, 56, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 59, 3);
+ BKE_gpencil_stroke_add_points(gps, data18, 59, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 100, 3);
+ BKE_gpencil_stroke_add_points(gps, data19, 100, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Eyes, 136, 3);
+ BKE_gpencil_stroke_add_points(gps, data20, 136, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 353, 3);
+ BKE_gpencil_stroke_add_points(gps, data21, 353, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 309, 3);
+ BKE_gpencil_stroke_add_points(gps, data22, 309, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 209, 3);
+ BKE_gpencil_stroke_add_points(gps, data23, 209, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 133, 3);
+ BKE_gpencil_stroke_add_points(gps, data24, 133, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 389, 3);
+ BKE_gpencil_stroke_add_points(gps, data25, 389, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 41, 3);
+ BKE_gpencil_stroke_add_points(gps, data26, 41, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 77, 3);
+ BKE_gpencil_stroke_add_points(gps, data27, 77, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 257, 3);
+ BKE_gpencil_stroke_add_points(gps, data28, 257, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 205, 3);
+ BKE_gpencil_stroke_add_points(gps, data29, 205, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 3);
+ BKE_gpencil_stroke_add_points(gps, data30, 33, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 37, 3);
+ BKE_gpencil_stroke_add_points(gps, data31, 37, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 201, 3);
+ BKE_gpencil_stroke_add_points(gps, data32, 201, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 69, 3);
+ BKE_gpencil_stroke_add_points(gps, data33, 69, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 57, 3);
+ BKE_gpencil_stroke_add_points(gps, data34, 57, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 261, 3);
+ BKE_gpencil_stroke_add_points(gps, data35, 261, mat);
+
+ /* update depsgraph */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+}
+
+
+/* ***************************************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index bd9bfcf7025..52642fb2570 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -48,6 +48,7 @@
#include "BLT_translation.h"
+#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -60,6 +61,9 @@
#include "BKE_library.h"
#include "BKE_report.h"
#include "BKE_screen.h"
+#include "BKE_object_deform.h"
+#include "BKE_colortools.h"
+#include "BKE_material.h"
#include "UI_interface.h"
@@ -80,6 +84,9 @@
#include "GPU_immediate_util.h"
#include "GPU_state.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "gpencil_intern.h"
/* ************************************************ */
@@ -89,7 +96,9 @@
typedef struct tGP_BrushEditData {
/* Current editor/region/etc. */
/* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */
+ Depsgraph *depsgraph;
Scene *scene;
+ Object *object;
ScrArea *sa;
ARegion *ar;
@@ -114,6 +123,10 @@ typedef struct tGP_BrushEditData {
/* Start of new sculpt stroke */
bool first;
+ /* Is multiframe editing enabled, and are we using falloff for that? */
+ bool is_multiframe;
+ bool use_multiframe_falloff;
+
/* Current frame */
int cfra;
@@ -128,6 +141,13 @@ typedef struct tGP_BrushEditData {
/* - effect vector (e.g. 2D/3D translation for grab brush) */
float dvec[3];
+ /* - multiframe falloff factor */
+ float mf_falloff;
+
+ /* active vertex group */
+ int vrgroup;
+
+
/* brush geometry (bounding box) */
rcti brush_rect;
@@ -147,12 +167,34 @@ typedef struct tGP_BrushEditData {
/* Callback for performing some brush operation on a single point */
-typedef bool (*GP_BrushApplyCb)(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
+typedef bool (*GP_BrushApplyCb)(tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
const int radius, const int co[2]);
/* ************************************************ */
/* Utility Functions */
+/* apply lock axis reset */
+static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso, bGPDspoint *pt, const float save_pt[3])
+{
+ if (gso->sa->spacetype != SPACE_VIEW3D) {
+ return;
+ }
+
+ ToolSettings *ts = gso->scene->toolsettings;
+ int axis = ts->gp_sculpt.lock_axis;
+
+ /* lock axis control */
+ if (axis == 1) {
+ pt->x = save_pt[0];
+ }
+ if (axis == 2) {
+ pt->y = save_pt[1];
+ }
+ if (axis == 3) {
+ pt->z = save_pt[2];
+ }
+}
+
/* Context ---------------------------------------- */
/* Get the sculpting settings */
@@ -162,10 +204,18 @@ static GP_BrushEdit_Settings *gpsculpt_get_settings(Scene *scene)
}
/* Get the active brush */
-static GP_EditBrush_Data *gpsculpt_get_brush(Scene *scene)
+static GP_EditBrush_Data *gpsculpt_get_brush(Scene *scene, bool is_weight_mode)
{
GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt;
- return &gset->brush[gset->brushtype];
+ GP_EditBrush_Data *brush = NULL;
+ if (is_weight_mode) {
+ brush = &gset->brush[gset->weighttype];
+ }
+ else {
+ brush = &gset->brush[gset->brushtype];
+ }
+
+ return brush;
}
/* Brush Operations ------------------------------- */
@@ -181,6 +231,14 @@ static bool gp_brush_invert_check(tGP_BrushEditData *gso)
invert ^= true;
}
+ /* set temporary status */
+ if (invert) {
+ gso->brush->flag |= GP_EDITBRUSH_FLAG_TMP_INVERT;
+ }
+ else {
+ gso->brush->flag &= ~GP_EDITBRUSH_FLAG_TMP_INVERT;
+ }
+
return invert;
}
@@ -208,6 +266,9 @@ static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, c
influence *= fac;
}
+ /* apply multiframe falloff */
+ influence *= gso->mf_falloff;
+
/* return influence */
return influence;
}
@@ -222,29 +283,34 @@ static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, c
/* Smooth Brush */
/* A simple (but slower + inaccurate) smooth-brush implementation to test the algorithm for stroke smoothing */
-static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_smooth_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
- GP_EditBrush_Data *brush = gso->brush;
+ // GP_EditBrush_Data *brush = gso->brush;
float inf = gp_brush_influence_calc(gso, radius, co);
- bool affect_pressure = (brush->flag & GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE) != 0;
/* need one flag enabled by default */
- if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION |
- GP_BRUSHEDIT_FLAG_APPLY_STRENGTH |
- GP_BRUSHEDIT_FLAG_APPLY_THICKNESS)) == 0)
+ if ((gso->settings->flag &
+ (GP_BRUSHEDIT_FLAG_APPLY_POSITION |
+ GP_BRUSHEDIT_FLAG_APPLY_STRENGTH |
+ GP_BRUSHEDIT_FLAG_APPLY_THICKNESS |
+ GP_BRUSHEDIT_FLAG_APPLY_UV)) == 0)
{
gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
}
/* perform smoothing */
if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_POSITION) {
- gp_smooth_stroke(gps, i, inf, affect_pressure);
+ BKE_gpencil_smooth_stroke(gps, pt_index, inf);
}
if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_STRENGTH) {
- gp_smooth_stroke_strength(gps, i, inf);
+ BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
}
if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_THICKNESS) {
- gp_smooth_stroke_thickness(gps, i, inf);
+ BKE_gpencil_smooth_stroke_thickness(gps, pt_index, inf);
+ }
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_UV) {
+ BKE_gpencil_smooth_stroke_uv(gps, pt_index, inf);
}
return true;
@@ -254,10 +320,11 @@ static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i
/* Line Thickness Brush */
/* Make lines thicker or thinner by the specified amounts */
-static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_thickness_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + i;
+ bGPDspoint *pt = gps->points + pt_index;
float inf;
/* Compute strength of effect
@@ -294,28 +361,29 @@ static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
/* Make color more or less transparent by the specified amounts */
static bool gp_brush_strength_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int i,
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + i;
+ bGPDspoint *pt = gps->points + pt_index;
float inf;
/* Compute strength of effect
- * - We divide the strength by 10, so that users can set "sane" values.
+ * - We divide the strength, 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;
+ inf = gp_brush_influence_calc(gso, radius, co) / 20.0f;
/* apply */
- // XXX: this is much too strong, and it should probably do some smoothing with the surrounding stuff
if (gp_brush_invert_check(gso)) {
- /* make line thinner - reduce stroke pressure */
+ /* make line more transparent - reduce alpha factor */
pt->strength -= inf;
}
else {
- /* make line thicker - increase stroke pressure */
+ /* make line more opaque - increase stroke strength */
pt->strength += inf;
}
+ /* smooth the strength */
+ BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
/* Strength should stay within [0.0, 1.0] */
CLAMP(pt->strength, 0.0f, 1.0f);
@@ -382,8 +450,9 @@ static void gp_brush_grab_stroke_init(tGP_BrushEditData *gso, bGPDstroke *gps)
}
/* store references to stroke points in the initial stage */
-static bool gp_brush_grab_store_points(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_grab_store_points(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
float inf = gp_brush_influence_calc(gso, radius, co);
@@ -392,7 +461,7 @@ static bool gp_brush_grab_store_points(tGP_BrushEditData *gso, bGPDstroke *gps,
BLI_assert(data->size < data->capacity);
/* insert this point into the set of affected points */
- data->points[data->size] = i;
+ data->points[data->size] = pt_index;
data->weights[data->size] = inf;
data->size++;
@@ -431,7 +500,7 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
/* Apply grab transform to all relevant points of the affected strokes */
static void gp_brush_grab_apply_cached(
- tGP_BrushEditData *gso, bGPDstroke *gps, bool parented, float diff_mat[4][4])
+ tGP_BrushEditData *gso, bGPDstroke *gps, float diff_mat[4][4])
{
tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
int i;
@@ -443,23 +512,21 @@ static void gp_brush_grab_apply_cached(
/* adjust the amount of displacement to apply */
mul_v3_v3fl(delta, gso->dvec, data->weights[i]);
- if (!parented) {
- /* apply */
- add_v3_v3(&pt->x, delta);
- }
- else {
- float fpt[3];
- /* apply transformation */
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- /* apply */
- add_v3_v3(fpt, delta);
- copy_v3_v3(&pt->x, fpt);
- /* 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);
- }
+ float fpt[3];
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
+ /* apply transformation */
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* 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);
}
}
@@ -480,10 +547,14 @@ static void gp_brush_grab_stroke_free(void *ptr)
/* Push Brush */
/* NOTE: Depends on gp_brush_grab_calc_dvec() */
-static bool gp_brush_push_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_push_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + i;
+ bGPDspoint *pt = gps->points + pt_index;
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
+
float inf = gp_brush_influence_calc(gso, radius, co);
float delta[3] = {0.0f};
@@ -493,6 +564,9 @@ static bool gp_brush_push_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
/* apply */
add_v3_v3(&pt->x, delta);
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
+
/* done */
return true;
}
@@ -512,7 +586,8 @@ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso)
float *rvec = ED_view3d_cursor3d_get(gso->scene, v3d)->location;
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
- float mval_f[2] = {UNPACK2(gso->mval)};
+ float mval_f[2];
+ copy_v2fl_v2i(mval_f, gso->mval);
float mval_prj[2];
float dvec[3];
@@ -536,12 +611,15 @@ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso)
}
/* Shrink distance between midpoint and this point... */
-static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_pinch_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + i;
+ bGPDspoint *pt = gps->points + pt_index;
float fac, inf;
float vec[3];
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
/* Scale down standard influence value to get it more manageable...
* - No damping = Unmanageable at > 0.5 strength
@@ -571,6 +649,9 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
/* 3) Translate back to original space, with the shrinkage applied */
add_v3_v3v3(&pt->x, gso->dvec, vec);
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
+
/* done */
return true;
}
@@ -582,11 +663,14 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
* convert the rotated point and convert it into "data" space
*/
-static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_twist_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + i;
+ bGPDspoint *pt = gps->points + pt_index;
float angle, inf;
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
/* Angle to rotate by */
inf = gp_brush_influence_calc(gso, radius, co);
@@ -615,6 +699,9 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center (center is stored in dvec) */
mul_m3_v3(rmat, vec);
add_v3_v3v3(&pt->x, vec, gso->dvec); /* restore */
+
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
}
else {
const float axis[3] = {0.0f, 0.0f, 1.0f};
@@ -654,10 +741,13 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
/* Randomize Brush */
/* Apply some random jitter to the point */
-static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_randomize_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + i;
+ bGPDspoint *pt = gps->points + pt_index;
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
/* Amount of jitter to apply depends on the distance of the point to the cursor,
* as well as the strength of the brush
@@ -667,7 +757,8 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
/* need one flag enabled by default */
if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION |
GP_BRUSHEDIT_FLAG_APPLY_STRENGTH |
- GP_BRUSHEDIT_FLAG_APPLY_THICKNESS)) == 0)
+ GP_BRUSHEDIT_FLAG_APPLY_THICKNESS |
+ GP_BRUSHEDIT_FLAG_APPLY_UV)) == 0)
{
gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
}
@@ -710,6 +801,8 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
float dvec[3];
ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac);
add_v3_v3(&pt->x, dvec);
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
}
}
else {
@@ -749,11 +842,76 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
/* only limit lower value */
CLAMP_MIN(pt->pressure, 0.0f);
}
+ /* apply random to UV (use pressure) */
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_UV) {
+ if (BLI_rng_get_float(gso->rng) > 0.5f) {
+ pt->uv_rot += fac;
+ }
+ else {
+ pt->uv_rot -= fac;
+ }
+ CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
+ }
/* done */
return true;
}
+/* Weight Paint Brush */
+
+/* Change weight paint for vertex groups */
+static bool gp_brush_weight_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
+{
+ bGPDspoint *pt = gps->points + pt_index;
+ 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);
+ gso->vrgroup = 0;
+ }
+ }
+ /* get current weight */
+ float curweight = 0.0f;
+ for (int i = 0; i < dvert->totweight; i++) {
+ MDeformWeight *gpw = &dvert->dw[i];
+ if (gpw->def_nr == gso->vrgroup) {
+ curweight = gpw->weight;
+ break;
+ }
+ }
+
+ if (gp_brush_invert_check(gso)) {
+ /* reduce weight */
+ curweight -= inf;
+ }
+ else {
+ /* increase weight */
+ curweight += inf;
+ }
+
+ CLAMP(curweight, 0.0f, 1.0f);
+ BKE_gpencil_vgroup_add_point_weight(dvert, gso->vrgroup, curweight);
+
+ /* weight should stay within [0.0, 1.0] */
+ if (pt->pressure < 0.0f)
+ pt->pressure = 0.0f;
+
+ return true;
+}
+
+
+
/* ************************************************ */
/* Non Callback-Based Brushes */
@@ -827,7 +985,7 @@ static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso)
/* Init colormap for mapping between the pasted stroke's source colour(names)
* and the final colours that will be used here instead...
*/
- data->new_colors = gp_copybuf_validate_colormap(gso->gpd);
+ data->new_colors = gp_copybuf_validate_colormap(C);
}
/* Free custom data used for "clone" brush */
@@ -857,9 +1015,12 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
{
tGPSB_CloneBrushData *data = gso->customdata;
- Scene *scene = gso->scene;
+ Object *ob = CTX_data_active_object(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, true);
bGPDstroke *gps;
float delta[3];
@@ -882,17 +1043,22 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
new_stroke = MEM_dupallocN(gps);
new_stroke->points = MEM_dupallocN(gps->points);
+ new_stroke->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, new_stroke);
new_stroke->triangles = MEM_dupallocN(gps->triangles);
new_stroke->next = new_stroke->prev = NULL;
BLI_addtail(&gpf->strokes, new_stroke);
/* Fix color references */
- BLI_assert(new_stroke->colorname[0] != '\0');
- new_stroke->palcolor = BLI_ghash_lookup(data->new_colors, new_stroke->colorname);
-
- BLI_assert(new_stroke->palcolor != NULL);
- BLI_strncpy(new_stroke->colorname, new_stroke->palcolor->info, sizeof(new_stroke->colorname));
+ Material *ma = BLI_ghash_lookup(data->new_colors, &new_stroke->mat_nr);
+ if ((ma) && (BKE_object_material_slot_find_index(ob, ma) > 0)) {
+ gps->mat_nr = BKE_object_material_slot_find_index(ob, ma) - 1;
+ CLAMP_MIN(gps->mat_nr, 0);
+ }
+ else {
+ gps->mat_nr = 0; /* only if the color is not found */
+ }
/* Adjust all the stroke's points, so that the strokes
* get pasted relative to where the cursor is now
@@ -977,57 +1143,6 @@ static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso)
}
/* ************************************************ */
-/* Cursor drawing */
-
-/* Helper callback for drawing the cursor itself */
-static void gp_brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata))
-{
- GP_EditBrush_Data *brush = gpsculpt_get_brush(CTX_data_scene(C));
-
- if (brush) {
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- GPU_line_smooth(true);
- GPU_blend(true);
-
- /* Inner Ring: Light color for action of the brush */
- /* TODO: toggle between add and remove? */
- immUniformColor4ub(255, 255, 255, 200);
- imm_draw_circle_wire_2d(pos, x, y, brush->size, 40);
-
- /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
- immUniformColor3ub(30, 30, 30);
- imm_draw_circle_wire_2d(pos, x, y, brush->size + 1, 40);
-
- immUnbindProgram();
-
- GPU_blend(false);
- GPU_line_smooth(false);
- }
-}
-
-/* Turn brush cursor in on/off */
-static void gpencil_toggle_brush_cursor(bContext *C, bool enable)
-{
- GP_BrushEdit_Settings *gset = gpsculpt_get_settings(CTX_data_scene(C));
-
- if (gset->paintcursor && !enable) {
- /* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
- gset->paintcursor = NULL;
- }
- else if (enable) {
- /* enable cursor */
- gset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- NULL,
- gp_brush_drawcursor, NULL);
- }
-}
-
-
-/* ************************************************ */
/* Header Info for GPencil Sculpt */
static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
@@ -1054,17 +1169,40 @@ 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);
+ Object *ob = CTX_data_active_object(C);
+
+ const bool is_weight_mode = ob->mode == OB_MODE_GPENCIL_WEIGHT;
+ /* set the brush using the tool */
+ GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
+ eGP_EditBrush_Types mode = RNA_enum_get(op->ptr, "mode");
+ const bool keep_brush = RNA_boolean_get(op->ptr, "keep_brush");
+
+ if (!keep_brush) {
+ if (is_weight_mode) {
+ gset->weighttype = mode;
+ }
+ else {
+ gset->brushtype = mode;
+ }
+ }
tGP_BrushEditData *gso;
/* setup operator data */
gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData");
op->customdata = gso;
+ gso->depsgraph = CTX_data_depsgraph(C);
/* store state */
gso->settings = gpsculpt_get_settings(scene);
- gso->brush = gpsculpt_get_brush(scene);
+ gso->brush = gpsculpt_get_brush(scene, is_weight_mode);
- gso->brush_type = gso->settings->brushtype;
+ 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);
@@ -1078,10 +1216,31 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */
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->sa = CTX_wm_area(C);
gso->ar = 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_BRUSHEDIT_FLAG_FRAME_FALLOFF) != 0;
+
+ /* init multiedit falloff curve data before doing anything,
+ * so we won't have to do it again later
+ */
+ if (gso->is_multiframe) {
+ curvemapping_initialize(ts->gp_sculpt.cur_falloff);
+ }
+
/* initialise custom data for brushes */
switch (gso->brush_type) {
case GP_EDITBRUSH_TYPE_CLONE:
@@ -1133,9 +1292,10 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
gpsculpt_brush_header_set(C, gso);
/* setup cursor drawing */
- WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
- gpencil_toggle_brush_cursor(C, true);
-
+ //WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
+ if (gso->sa->spacetype != SPACE_VIEW3D) {
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ }
return true;
}
@@ -1179,7 +1339,12 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
/* disable cursor and headerprints */
ED_workspace_status_text(C, NULL);
WM_cursor_modal_restore(win);
- gpencil_toggle_brush_cursor(C, false);
+ if (gso->sa->spacetype != SPACE_VIEW3D) {
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ }
+
+ /* disable temp invert flag */
+ gso->brush->flag &= ~GP_EDITBRUSH_FLAG_TMP_INVERT;
/* free operator data */
MEM_freeN(gso);
@@ -1197,13 +1362,13 @@ static bool gpsculpt_brush_poll(bContext *C)
static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
{
- Scene *scene = gso->scene;
bGPdata *gpd = gso->gpd;
+
bGPDlayer *gpl;
- int cfra = CFRA;
+ int cfra_eval = (int)DEG_get_ctime(gso->depsgraph);
/* only try to add a new frame if this is the first stroke, or the frame has changed */
- if ((gpd == NULL) || (cfra == gso->cfra))
+ if ((gpd == NULL) || (cfra_eval == gso->cfra))
return;
/* go through each layer, and ensure that we've got a valid frame to use */
@@ -1217,21 +1382,21 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
* spent too much time editing the wrong frame...
*/
// XXX: should this be allowed when framelock is enabled?
- if (gpf->framenum != cfra) {
- BKE_gpencil_frame_addcopy(gpl, cfra);
+ if (gpf->framenum != cfra_eval) {
+ BKE_gpencil_frame_addcopy(gpl, cfra_eval);
}
}
}
/* save off new current frame, so that next update works fine */
- gso->cfra = cfra;
+ gso->cfra = cfra_eval;
}
/* Apply ----------------------------------------------- */
/* Apply brush operation to points in this stroke */
static bool gpsculpt_brush_do_stroke(
- tGP_BrushEditData *gso, bGPDstroke *gps, bool parented,
+ tGP_BrushEditData *gso, bGPDstroke *gps,
float diff_mat[4][4], GP_BrushApplyCb apply)
{
GP_SpaceConversion *gsc = &gso->gsc;
@@ -1246,14 +1411,9 @@ static bool gpsculpt_brush_do_stroke(
bool changed = false;
if (gps->totpoints == 1) {
- if (!parented) {
- gp_point_to_xy(gsc, gps, gps->points, &pc1[0], &pc1[1]);
- }
- else {
- bGPDspoint pt_temp;
- gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
- gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
- }
+ bGPDspoint pt_temp;
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(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])) {
@@ -1280,19 +1440,12 @@ static bool gpsculpt_brush_do_stroke(
continue;
}
}
- if (!parented) {
- gp_point_to_xy(gsc, gps, pt1, &pc1[0], &pc1[1]);
- gp_point_to_xy(gsc, gps, pt2, &pc2[0], &pc2[1]);
- }
- else {
- 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]);
- }
+ 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])) ||
@@ -1342,9 +1495,114 @@ static bool gpsculpt_brush_do_stroke(
return changed;
}
+/* Apply sculpt brushes to strokes in the given frame */
+static bool gpsculpt_brush_do_frame(
+ bContext *C, tGP_BrushEditData *gso,
+ bGPDlayer *gpl, bGPDframe *gpf,
+ float diff_mat[4][4])
+{
+ bool changed = false;
+ Object *ob = CTX_data_active_object(C);
+
+ 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;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+
+ switch (gso->brush_type) {
+ case GP_EDITBRUSH_TYPE_SMOOTH: /* Smooth strokes */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_smooth_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_thickness_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_STRENGTH: /* Adjust stroke color strength */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_strength_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_GRAB: /* Grab points */
+ {
+ if (gso->first) {
+ /* First time this brush stroke is being applied:
+ * 1) Prepare data buffers (init/clear) for this stroke
+ * 2) Use the points now under the cursor
+ */
+ gp_brush_grab_stroke_init(gso, gps);
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points);
+ }
+ else {
+ /* Apply effect to the stored points */
+ gp_brush_grab_apply_cached(gso, gps, diff_mat);
+ changed |= true;
+ }
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_PUSH: /* Push points */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_push_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_pinch_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_twist_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Apply jitter */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_randomize_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_WEIGHT: /* Adjust vertex group weight */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_weight_apply);
+ break;
+ }
+
+
+ default:
+ printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
+ break;
+ }
+ /* Triangulation must be calculated if changed */
+ if (changed) {
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+ }
+ }
+
+ return changed;
+}
+
/* 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_depsgraph(C); \
+ Object *obact = gso->object;
+ bGPdata *gpd = gso->gpd;
bool changed = false;
/* Calculate brush-specific data which applies equally to all points */
@@ -1378,104 +1636,53 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
/* Find visible strokes, and perform operations on those if hit */
- float diff_mat[4][4];
- bool parented = false;
-
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL)
+ /* If no active frame, don't do anything... */
+ if (gpl->actframe == NULL) {
continue;
-
- /* calculate difference matrix if parent object */
- if (gpl->parent != NULL) {
- ED_gpencil_parent_location(gpl, diff_mat);
- parented = true;
}
- else {
- parented = false;
- }
-
- 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;
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
- continue;
- }
- switch (gso->brush_type) {
- case GP_EDITBRUSH_TYPE_SMOOTH: /* Smooth strokes */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_smooth_apply);
- break;
- }
+ /* calculate difference matrix */
+ float diff_mat[4][4];
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
- case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_thickness_apply);
- break;
- }
+ /* Active Frame or MultiFrame? */
+ if (gso->is_multiframe) {
+ /* init multiframe falloff options */
+ int f_init = 0;
+ int f_end = 0;
- case GP_EDITBRUSH_TYPE_STRENGTH: /* Adjust stroke color strength */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_strength_apply);
- break;
- }
+ if (gso->use_multiframe_falloff) {
+ BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
+ }
- case GP_EDITBRUSH_TYPE_GRAB: /* Grab points */
- {
- if (gso->first) {
- /* First time this brush stroke is being applied:
- * 1) Prepare data buffers (init/clear) for this stroke
- * 2) Use the points now under the cursor
- */
- gp_brush_grab_stroke_init(gso, gps);
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_grab_store_points);
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* 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 {
- /* Apply effect to the stored points */
- gp_brush_grab_apply_cached(gso, gps, parented, diff_mat);
- changed |= true;
+ /* No falloff */
+ gso->mf_falloff = 1.0f;
}
- break;
- }
-
- case GP_EDITBRUSH_TYPE_PUSH: /* Push points */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_push_apply);
- break;
- }
-
- case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_pinch_apply);
- break;
- }
- case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_twist_apply);
- break;
+ /* affect strokes in this frame */
+ changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat);
}
-
- case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Apply jitter */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_randomize_apply);
- break;
- }
-
- default:
- printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
- break;
- }
- /* Triangulation must be calculated if changed */
- if (changed) {
- gps->flag |= GP_STROKE_RECALC_CACHES;
- gps->tot_triangles = 0;
}
}
+ else {
+ /* 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;
@@ -1529,6 +1736,7 @@ static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itempt
/* Updates */
if (changed) {
+ DEG_id_tag_update(&gso->gpd->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
@@ -1852,6 +2060,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
/* Redraw toolsettings (brush settings)? */
if (redraw_toolsettings) {
+ DEG_id_tag_update(&gso->gpd->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
}
@@ -1860,6 +2069,19 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
/* Operator --------------------------------------------- */
+static const EnumPropertyItem prop_gpencil_sculpt_brush_items[] = {
+ {GP_EDITBRUSH_TYPE_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth stroke points" },
+ {GP_EDITBRUSH_TYPE_THICKNESS, "THICKNESS", 0, "Thickness", "Adjust thickness of strokes" },
+ {GP_EDITBRUSH_TYPE_STRENGTH, "STRENGTH", 0, "Strength", "Adjust color strength of strokes" },
+ {GP_EDITBRUSH_TYPE_GRAB, "GRAB", 0, "Grab", "Translate the set of points initially within the brush circle" },
+ {GP_EDITBRUSH_TYPE_PUSH, "PUSH", 0, "Push", "Move points out of the way, as if combing them" },
+ {GP_EDITBRUSH_TYPE_TWIST, "TWIST", 0, "Twist", "Rotate points around the midpoint of the brush" },
+ {GP_EDITBRUSH_TYPE_PINCH, "PINCH", 0, "Pinch", "Pull points towards the midpoint of the brush" },
+ {GP_EDITBRUSH_TYPE_RANDOMIZE, "RANDOMIZE", 0, "Randomize", "Introduce jitter/randomness into strokes" },
+ {GP_EDITBRUSH_TYPE_CLONE, "CLONE", 0, "Clone", "Paste copies of the strokes stored on the clipboard" },
+ {GP_EDITBRUSH_TYPE_WEIGHT, "WEIGHT", 0, "Weight", "Weight Paint" },
+ {0, NULL, 0, NULL, NULL }
+};
void GPENCIL_OT_brush_paint(wmOperatorType *ot)
{
@@ -1879,13 +2101,20 @@ void GPENCIL_OT_brush_paint(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
/* properties */
+ ot->prop = RNA_def_enum(ot->srna, "mode", prop_gpencil_sculpt_brush_items, 0, "Mode", "Brush mode");
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
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",
"Enter a mini 'sculpt-mode' if enabled, otherwise, exit after drawing a single stroke");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "keep_brush", false, "Keep Brush",
+ "Keep current brush activated");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 79bfc5149ba..f662e9b42be 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -56,7 +56,6 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_workspace_types.h"
#include "BKE_collection.h"
#include "BKE_context.h"
@@ -74,6 +73,7 @@
#include "BKE_tracking.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "UI_interface.h"
@@ -149,28 +149,24 @@ static const EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), Poi
* - assumes that the active space is the 3D-View
*/
static void gp_strokepoint_convertcoords(
- bContext *C, bGPDlayer *gpl, bGPDstroke *gps, bGPDspoint *source_pt,
+ bContext *C, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, bGPDspoint *source_pt,
float p3d[3], const rctf *subrect)
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C); \
+ Object *obact = CTX_data_active_object(C);
bGPDspoint mypt, *pt;
float diff_mat[4][4];
pt = &mypt;
- /* calculate difference matrix if parent object */
- if (gpl->parent == NULL) {
- copy_v3_v3(&pt->x, &source_pt->x);
- }
- else {
- /* apply parent transform */
- float fpt[3];
- ED_gpencil_parent_location(gpl, diff_mat);
- mul_v3_m4v3(fpt, diff_mat, &source_pt->x);
- copy_v3_v3(&pt->x, fpt);
- }
+ /* apply parent transform */
+ float fpt[3];
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ mul_v3_m4v3(fpt, diff_mat, &source_pt->x);
+ copy_v3_v3(&pt->x, fpt);
if (gps->flag & GP_STROKE_3DSPACE) {
@@ -591,7 +587,7 @@ static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const fl
}
}
-static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
+static void gp_stroke_to_path(bContext *C, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
const bool add_end_point, tGpTimingData *gtd)
{
@@ -655,7 +651,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
bp = &nu->bp[old_nbp - 1];
/* First point */
- gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect);
if (prev_bp) {
interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
if (do_gtd) {
@@ -676,7 +672,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
/* Second point */
/* Note dt2 is always negative, which marks the gap. */
if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect);
interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
if (do_gtd) {
dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
@@ -697,9 +693,9 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
float p[3], next_p[3];
float dt = 0.0f;
- gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect);
if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect);
interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
if (do_gtd) {
dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
@@ -728,10 +724,10 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
i++, pt++, bp++)
{
float p[3];
- float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC;
+ float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC;
/* get coordinates to add at */
- gp_strokepoint_convertcoords(C, gpl, gps, pt, p, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, p, subrect);
gp_stroke_to_path_add_point(gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time,
width, rad_fac, minmax_weights);
@@ -801,7 +797,7 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt,
}
}
-static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
+static void gp_stroke_to_bezier(bContext *C, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
const bool add_end_point, tGpTimingData *gtd)
{
@@ -843,12 +839,12 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
/* get initial coordinates */
pt = gps->points;
if (tot) {
- gp_strokepoint_convertcoords(C, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
if (tot > 1) {
- gp_strokepoint_convertcoords(C, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
}
if (stitch && tot > 2) {
- gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect);
}
}
@@ -967,7 +963,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
/* add points */
for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
- float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC;
+ float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC;
if (i || old_nbezt) {
interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
@@ -991,7 +987,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
copy_v3_v3(p3d_cur, p3d_next);
if (i + 2 < tot) {
- gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect);
}
prev_bezt = bezt;
@@ -1130,10 +1126,12 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd)
{
struct Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Collection *collection = CTX_data_collection(C);
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0);
bGPDstroke *gps, *prev_gps = NULL;
Object *ob;
Curve *cu;
@@ -1192,12 +1190,12 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
switch (mode) {
case GP_STROKECONVERT_PATH:
- gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
+ gp_stroke_to_path(C, gpd, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
add_start_point, add_end_point, gtd);
break;
case GP_STROKECONVERT_CURVE:
case GP_STROKECONVERT_POLY: /* convert after */
- gp_stroke_to_bezier(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
+ gp_stroke_to_bezier(C, gpd, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
add_start_point, add_end_point, gtd);
break;
default:
@@ -1238,7 +1236,9 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
*/
static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
bGPDframe *gpf = NULL;
bGPDstroke *gps = NULL;
bGPDspoint *pt;
@@ -1246,7 +1246,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, 0)) || !(gps = gpf->strokes.first))
+ if (!gpl || !(gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0)) || !(gps = gpf->strokes.first))
return false;
do {
@@ -1294,10 +1294,12 @@ static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UN
static bool gp_convert_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
bGPDlayer *gpl = NULL;
bGPDframe *gpf = NULL;
ScrArea *sa = CTX_wm_area(C);
- Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
/* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
@@ -1305,7 +1307,7 @@ static bool gp_convert_poll(bContext *C)
*/
return ((sa && sa->spacetype == SPACE_VIEW3D) &&
(gpl = BKE_gpencil_layer_getactive(gpd)) &&
- (gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0)) &&
+ (gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0)) &&
(gpf->strokes.first) &&
(OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL));
}
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index c28fea0fc41..dd1852ca8ce 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -46,18 +46,32 @@
#include "BLT_translation.h"
+#include "DNA_anim_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
-#include "DNA_gpencil_types.h"
-#include "BKE_colortools.h"
+#include "BKE_main.h"
+#include "BKE_brush.h"
+#include "BKE_animsys.h"
#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_fcurve.h"
+#include "BKE_global.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
+#include "BKE_material.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -72,8 +86,13 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "ED_object.h"
#include "ED_gpencil.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
#include "gpencil_intern.h"
/* ************************************************ */
@@ -84,9 +103,9 @@
/* add new datablock - wrapper around API */
static int gp_data_add_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
- ToolSettings *ts = CTX_data_tool_settings(C);
+ PointerRNA gpd_owner = {{NULL}};
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner);
+ bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner);
if (gpd_ptr == NULL) {
BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
@@ -94,19 +113,36 @@ static int gp_data_add_exec(bContext *C, wmOperator *op)
}
else {
/* decrement user count and add new datablock */
- bGPdata *gpd = (*gpd_ptr);
+ /* TODO: if a datablock exists, we should make a copy of it instead of starting fresh (as in other areas) */
+ Main *bmain = CTX_data_main(C);
- id_us_min(&gpd->id);
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
+ /* decrement user count of old GP datablock */
+ if (*gpd_ptr) {
+ bGPdata *gpd = (*gpd_ptr);
+ id_us_min(&gpd->id);
+ }
- /* if not exist brushes, create a new set */
- if (ts) {
- if (BLI_listbase_is_empty(&ts->gp_brushes)) {
- /* create new brushes */
- BKE_gpencil_brush_init_presets(ts);
- }
+ /* add new datablock, with a single layer ready to use (so users don't have to perform an extra step) */
+ if (is_annotation) {
+ bGPdata *gpd = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
+ *gpd_ptr = gpd;
+
+ /* tag for annotations */
+ gpd->flag |= GP_DATA_ANNOTATIONS;
+
+ /* add new layer (i.e. a "note") */
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
}
+ else {
+ /* GP Object Case - This shouldn't happen! */
+ *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
+ /* add default sets of colors and brushes */
+ ED_gpencil_add_defaults(C);
+
+ /* add new layer */
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
+ }
}
/* notifiers */
@@ -185,28 +221,42 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot)
/* add new layer - wrapper around API */
static int gp_layer_add_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
- ToolSettings *ts = CTX_data_tool_settings(C);
+ PointerRNA gpd_owner = {{NULL}};
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner);
+ bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner);
/* if there's no existing Grease-Pencil data there, add some */
if (gpd_ptr == NULL) {
BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
return OPERATOR_CANCELLED;
}
- if (*gpd_ptr == NULL)
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
- /* if not exist brushes, create a new set */
- if (ts) {
- if (BLI_listbase_is_empty(&ts->gp_brushes)) {
- /* create new brushes */
- BKE_gpencil_brush_init_presets(ts);
+ if (*gpd_ptr == NULL) {
+ Main *bmain = CTX_data_main(C);
+ if (is_annotation) {
+ /* Annotations */
+ *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
+
+ /* mark as annotation */
+ (*gpd_ptr)->flag |= GP_DATA_ANNOTATIONS;
+ }
+ else {
+ /* GP Object */
+ /* NOTE: This shouldn't actually happen in practice */
+ *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
+
+ /* add default sets of colors and brushes */
+ ED_gpencil_add_defaults(C);
}
}
/* add new layer now */
- BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
+ if (is_annotation) {
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
+ }
+ else {
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
+ }
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -219,7 +269,7 @@ void GPENCIL_OT_layer_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Add New Layer";
ot->idname = "GPENCIL_OT_layer_add";
- ot->description = "Add new Grease Pencil layer for the active Grease Pencil data-block";
+ ot->description = "Add new layer or note for the active data-block";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -257,6 +307,7 @@ static int gp_layer_remove_exec(bContext *C, wmOperator *op)
BKE_gpencil_layer_delete(gpd, gpl);
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -296,6 +347,7 @@ 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)) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
@@ -346,6 +398,7 @@ static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
BKE_gpencil_layer_setactive(gpd, new_layer);
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -366,6 +419,154 @@ void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ********************* Duplicate Frame ************************** */
+enum {
+ GP_FRAME_DUP_ACTIVE = 0,
+ GP_FRAME_DUP_ALL = 1
+};
+
+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);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
+
+ if (mode == 0) {
+ BKE_gpencil_frame_addcopy(gpl, cfra_eval);
+ }
+ else {
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
+ BKE_gpencil_frame_addcopy(gpl, cfra_eval);
+ }
+ }
+
+ }
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_frame_duplicate(wmOperatorType *ot)
+{
+ static const EnumPropertyItem duplicate_mode[] = {
+ { GP_FRAME_DUP_ACTIVE, "ACTIVE", 0, "Active", "Duplicate frame in active layer only" },
+ { GP_FRAME_DUP_ALL, "ALL", 0, "All", "Duplicate active frames in all layers" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+
+ /* identifiers */
+ ot->name = "Duplicate Frame";
+ ot->idname = "GPENCIL_OT_frame_duplicate";
+ ot->description = "Make a copy of the active Grease Pencil Frame";
+
+ /* callbacks */
+ ot->exec = gp_frame_duplicate_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
+}
+
+/* ********************* Clean Fill Boundaries on Frame ************************** */
+enum {
+ GP_FRAME_CLEAN_FILL_ACTIVE = 0,
+ GP_FRAME_CLEAN_FILL_ALL = 1
+};
+
+static int gp_frame_clean_fill_exec(bContext *C, wmOperator *op)
+{
+ bool changed = false;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (mode == GP_FRAME_CLEAN_FILL_ALL) {
+ init_gpf = gpl->frames.first;
+ }
+
+ 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;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ /* free stroke */
+ if (gps->flag & GP_STROKE_NOFILL) {
+ /* free stroke memory arrays, then stroke itself */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ MEM_SAFE_FREE(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_frame_clean_fill(wmOperatorType *ot)
+{
+ static const EnumPropertyItem duplicate_mode[] = {
+ { GP_FRAME_CLEAN_FILL_ACTIVE, "ACTIVE", 0, "Active Frame Only", "Clean active frame only" },
+ { GP_FRAME_CLEAN_FILL_ALL, "ALL", 0, "All Frames", "Clean all frames in all layers" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+ /* identifiers */
+ ot->name = "Clean Fill Boundaries";
+ ot->idname = "GPENCIL_OT_frame_clean_fill";
+ ot->description = "Remove 'no fill' boundary strokes";
+
+ /* callbacks */
+ ot->exec = gp_frame_clean_fill_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
+}
+
/* *********************** Hide Layers ******************************** */
static int gp_hide_exec(bContext *C, wmOperator *op)
@@ -394,6 +595,7 @@ static int gp_hide_exec(bContext *C, wmOperator *op)
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -481,6 +683,7 @@ static int gp_reveal_exec(bContext *C, wmOperator *op)
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -521,6 +724,7 @@ static int gp_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -558,6 +762,7 @@ static int gp_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -630,6 +835,7 @@ static int gp_isolate_layer_exec(bContext *C, wmOperator *op)
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -673,22 +879,28 @@ static int gp_merge_layer_exec(bContext *C, wmOperator *op)
BLI_ghash_insert(gh_frames_cur, SET_INT_IN_POINTER(gpf->framenum), gpf);
}
- /* read all frames from next layer */
+ /* read all frames from next layer and add any missing in current layer */
for (bGPDframe *gpf = gpl_next->frames.first; gpf; gpf = gpf->next) {
- /* try to find frame in active layer */
+ /* try to find frame in current layer */
bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, SET_INT_IN_POINTER(gpf->framenum));
if (!frame) {
- /* nothing found, create new */
+ bGPDframe *actframe = BKE_gpencil_layer_getframe(gpl_current, gpf->framenum, GP_GETFRAME_USE_PREV);
frame = BKE_gpencil_frame_addnew(gpl_current, gpf->framenum);
+ /* duplicate strokes of current active frame */
+ if (actframe) {
+ BKE_gpencil_frame_copy_strokes(actframe, frame);
+ }
}
/* add to tail all strokes */
BLI_movelisttolist(&frame->strokes, &gpf->strokes);
}
+
/* Now delete next layer */
BKE_gpencil_layer_delete(gpd, gpl_next);
BLI_ghash_free(gh_frames_cur, NULL, NULL);
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -750,6 +962,7 @@ static int gp_layer_change_exec(bContext *C, wmOperator *op)
BKE_gpencil_layer_setactive(gpd, gpl);
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -788,6 +1001,7 @@ enum {
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 = BKE_gpencil_layer_getactive(gpd);
bGPDstroke *gps;
@@ -797,79 +1011,95 @@ static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- bGPDframe *gpf = gpl->actframe;
- /* temp listbase to store selected strokes */
- ListBase selected = {NULL};
const int direction = RNA_enum_get(op->ptr, "direction");
- /* verify if any selected stroke is in the extreme of the stack and select to move */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- /* only if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- /* 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(gpl, gps) == false) {
- continue;
- }
- /* some stroke is already at front*/
- if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) {
- if (gps == gpf->strokes.last) {
- return OPERATOR_CANCELLED;
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* temp listbase to store selected strokes by layer */
+ ListBase selected = { NULL };
+ bGPDframe *gpf = gpl->actframe;
+ if (gpl->flag & GP_LAYER_LOCKED) {
+ continue;
+ }
+
+ if (gpf == NULL) {
+ continue;
+ }
+ bool gpf_lock = false;
+ /* verify if any selected stroke is in the extreme of the stack and select to move */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
}
- }
- /* some stroke is already at botom */
- if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) {
- if (gps == gpf->strokes.first) {
- return OPERATOR_CANCELLED;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+ /* some stroke is already at front*/
+ if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) {
+ if (gps == gpf->strokes.last) {
+ gpf_lock = true;
+ continue;
+ }
+ }
+ /* some stroke is already at botom */
+ if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) {
+ if (gps == gpf->strokes.first) {
+ gpf_lock = true;
+ continue;
+ }
+ }
+ /* add to list (if not locked) */
+ if (!gpf_lock) {
+ BLI_addtail(&selected, BLI_genericNodeN(gps));
}
}
- /* add to list */
- BLI_addtail(&selected, BLI_genericNodeN(gps));
}
- }
-
- /* Now do the movement of the stroke */
- switch (direction) {
- /* Bring to Front */
- case GP_STROKE_MOVE_TOP:
- for (LinkData *link = selected.first; link; link = link->next) {
- gps = link->data;
- BLI_remlink(&gpf->strokes, gps);
- BLI_addtail(&gpf->strokes, gps);
- }
- break;
- /* Bring Forward */
- case GP_STROKE_MOVE_UP:
- for (LinkData *link = selected.last; link; link = link->prev) {
- gps = link->data;
- BLI_listbase_link_move(&gpf->strokes, gps, 1);
- }
- break;
- /* Send Backward */
- case GP_STROKE_MOVE_DOWN:
- for (LinkData *link = selected.first; link; link = link->next) {
- gps = link->data;
- BLI_listbase_link_move(&gpf->strokes, gps, -1);
- }
- break;
- /* Send to Back */
- case GP_STROKE_MOVE_BOTTOM:
- for (LinkData *link = selected.last; link; link = link->prev) {
- gps = link->data;
- BLI_remlink(&gpf->strokes, gps);
- BLI_addhead(&gpf->strokes, gps);
+ /* Now do the movement of the stroke */
+ if (!gpf_lock) {
+ switch (direction) {
+ /* Bring to Front */
+ case GP_STROKE_MOVE_TOP:
+ for (LinkData *link = selected.first; link; link = link->next) {
+ gps = link->data;
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_addtail(&gpf->strokes, gps);
+ }
+ break;
+ /* Bring Forward */
+ case GP_STROKE_MOVE_UP:
+ for (LinkData *link = selected.last; link; link = link->prev) {
+ gps = link->data;
+ BLI_listbase_link_move(&gpf->strokes, gps, 1);
+ }
+ break;
+ /* Send Backward */
+ case GP_STROKE_MOVE_DOWN:
+ for (LinkData *link = selected.first; link; link = link->next) {
+ gps = link->data;
+ BLI_listbase_link_move(&gpf->strokes, gps, -1);
+ }
+ break;
+ /* Send to Back */
+ case GP_STROKE_MOVE_BOTTOM:
+ for (LinkData *link = selected.last; link; link = link->prev) {
+ gps = link->data;
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_addhead(&gpf->strokes, gps);
+ }
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- break;
- default:
- BLI_assert(0);
- break;
+ }
+ BLI_freelistN(&selected);
}
- BLI_freelistN(&selected);
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -890,58 +1120,70 @@ void GPENCIL_OT_stroke_arrange(wmOperatorType *ot)
ot->idname = "GPENCIL_OT_stroke_arrange";
ot->description = "Arrange selected strokes up/down in the drawing order of the active layer";
- /* api callbacks */
+ /* callbacks */
ot->exec = gp_stroke_arrange_exec;
ot->poll = gp_active_layer_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* properties */
ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_STROKE_MOVE_UP, "Direction", "");
}
+
/* ******************* Move Stroke to new color ************************** */
static int gp_stroke_change_color_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette;
- bGPDpalettecolor *color;
+ Object *ob = CTX_data_active_object(C);
+ Material *ma = give_current_material(ob, ob->actcol);
+ int idx = BKE_object_material_slot_find_index(ob, ma) - 1;
/* sanity checks */
if (ELEM(NULL, gpd)) {
return OPERATOR_CANCELLED;
}
- palette = BKE_gpencil_palette_getactive(gpd);
- color = BKE_gpencil_palettecolor_getactive(palette);
- if (ELEM(NULL, palette, color)) {
+ bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ if (ELEM(NULL, ma)) {
return OPERATOR_CANCELLED;
}
/* loop all strokes */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (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) {
- /* 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(gpl, gps) == false)
- continue;
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
- /* asign new color (only if different) */
- if ((STREQ(gps->colorname, color->info) == false) || (gps->palcolor != color)) {
- BLI_strncpy(gps->colorname, color->info, sizeof(gps->colorname));
- gps->palcolor = color;
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* 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;
+
+ /* asign new color */
+ gps->mat_nr = idx;
}
}
}
}
}
+ CTX_DATA_END;
+
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -954,9 +1196,12 @@ void GPENCIL_OT_stroke_change_color(wmOperatorType *ot)
ot->idname = "GPENCIL_OT_stroke_change_color";
ot->description = "Move selected strokes to active color";
- /* api callbacks */
+ /* callbacks */
ot->exec = gp_stroke_change_color_exec;
ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ******************* Lock color of non selected Strokes colors ************************** */
@@ -964,19 +1209,21 @@ void GPENCIL_OT_stroke_change_color(wmOperatorType *ot)
static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette;
+
+ Object *ob = CTX_data_active_object(C);
+
+ Material ***matar = give_matarar(ob);
+ short *totcol = give_totcolp(ob);
/* sanity checks */
if (ELEM(NULL, gpd))
return OPERATOR_CANCELLED;
- palette = BKE_gpencil_palette_getactive(gpd);
- if (ELEM(NULL, palette))
- return OPERATOR_CANCELLED;
-
/* first lock all colors */
- for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag |= PC_COLOR_LOCKED;
+ for (short i = 0; i < *totcol; i++) {
+ Material *tmp_ma = (*matar)[i];
+ tmp_ma->gp_style->flag |= GP_STYLE_COLOR_LOCKED;
+
}
/* loop all selected strokes and unlock any color */
@@ -991,14 +1238,14 @@ static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
continue;
}
/* unlock color */
- if (gps->palcolor != NULL) {
- gps->palcolor->flag &= ~PC_COLOR_LOCKED;
- }
+ Material *tmp_ma = (*matar)[gps->mat_nr];
+ tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
}
}
}
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1014,25 +1261,18 @@ void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
/* api callbacks */
ot->exec = gp_stroke_lock_color_exec;
ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ************************************************ */
/* Drawing Brushes Operators */
-/* ******************* Add New Brush ************************ */
-
-/* add new brush - wrapper around API */
-static int gp_brush_add_exec(bContext *C, wmOperator *op)
+/* ******************* Brush create presets ************************** */
+static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
{
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- /* if there's no existing container */
- if (ts == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for brush data to go");
- return OPERATOR_CANCELLED;
- }
- /* add new brush now */
- BKE_gpencil_brush_addnew(ts, DATA_("GP_Brush"), true);
+ BKE_brush_gpencil_presets(C);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -1040,513 +1280,760 @@ static int gp_brush_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_brush_add(wmOperatorType *ot)
+void GPENCIL_OT_brush_presets_create(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Brush";
- ot->idname = "GPENCIL_OT_brush_add";
- ot->description = "Add new Grease Pencil drawing brush for the active Grease Pencil data-block";
+ ot->name = "Create Preset Brushes";
+ ot->idname = "GPENCIL_OT_brush_presets_create";
+ ot->description = "Create a set of predefined Grease Pencil drawing brushes";
+
+ /* api callbacks */
+ ot->exec = gp_brush_presets_create_exec;
+ /* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* callbacks */
- ot->exec = gp_brush_add_exec;
- ot->poll = gp_add_poll;
}
-/* ******************* Remove Active Brush ************************* */
+/* ***************** Select Brush ************************ */
-static int gp_brush_remove_exec(bContext *C, wmOperator *op)
+static int gp_brush_select_exec(bContext *C, wmOperator *op)
{
ToolSettings *ts = CTX_data_tool_settings(C);
- bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
-
- /* sanity checks */
- if (ELEM(NULL, ts, brush))
- return OPERATOR_CANCELLED;
+ Main *bmain = CTX_data_main(C);
- if (BLI_listbase_count_at_most(&ts->gp_brushes, 2) < 2) {
- BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a brush, unable to delete the last one");
+ /* if there's no existing container */
+ if (ts == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere to go");
return OPERATOR_CANCELLED;
}
+ const int index = RNA_int_get(op->ptr, "index");
- /* make the brush before this the new active brush
- * - use the one after if this is the first
- * - if this is the only brush, this naturally becomes NULL
- */
- if (brush->prev)
- BKE_gpencil_brush_setactive(ts, brush->prev);
- else
- BKE_gpencil_brush_setactive(ts, brush->next);
-
- /* delete the brush now... */
- BKE_gpencil_brush_delete(ts, brush);
+ Paint *paint = BKE_brush_get_gpencil_paint(ts);
+ int i = 0;
+ for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+ if (brush->ob_mode == OB_MODE_GPENCIL_PAINT) {
+ if (i == index) {
+ BKE_paint_brush_set(paint, brush);
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ i++;
+ }
+ }
- return OPERATOR_FINISHED;
+ return OPERATOR_CANCELLED;
}
-void GPENCIL_OT_brush_remove(wmOperatorType *ot)
+void GPENCIL_OT_brush_select(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Remove Brush";
- ot->idname = "GPENCIL_OT_brush_remove";
- ot->description = "Remove active Grease Pencil drawing brush";
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->name = "Select Brush";
+ ot->idname = "GPENCIL_OT_brush_select";
+ ot->description = "Select a Grease Pencil drawing brush";
/* callbacks */
- ot->exec = gp_brush_remove_exec;
+ ot->exec = gp_brush_select_exec;
ot->poll = gp_active_brush_poll;
-}
-/* ********************** Change Brush ***************************** */
-
-static int gp_brush_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
-{
- uiPopupMenu *pup;
- uiLayout *layout;
-
- /* call the menu, which will call this operator again, hence the canceled */
- pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
- layout = UI_popup_menu_layout(pup);
- uiItemsEnumO(layout, "GPENCIL_OT_brush_change", "brush");
- UI_popup_menu_end(C, pup);
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- return OPERATOR_INTERFACE;
+ /* properties */
+ RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of Drawing Brush", 0, INT_MAX);
}
-static int gp_brush_change_exec(bContext *C, wmOperator *op)
+/* ***************** Select Sculpt Brush ************************ */
+
+static int gp_sculpt_select_exec(bContext *C, wmOperator *op)
{
ToolSettings *ts = CTX_data_tool_settings(C);
- bGPDbrush *brush = NULL;
- int brush_num = RNA_enum_get(op->ptr, "brush");
- /* Get brush or create new one */
- if (brush_num == -1) {
- /* Create brush */
- brush = BKE_gpencil_brush_addnew(ts, DATA_("GP_Brush"), true);
+ /* if there's no existing container */
+ if (ts == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere to go");
+ return OPERATOR_CANCELLED;
}
- else {
- /* Try to get brush */
- brush = BLI_findlink(&ts->gp_brushes, brush_num);
- if (brush == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent brush (index = %d)", brush_num);
- return OPERATOR_CANCELLED;
- }
+ const int index = RNA_int_get(op->ptr, "index");
+ GP_BrushEdit_Settings *gp_sculpt = &ts->gp_sculpt;
+ /* sanity checks */
+ if (ELEM(NULL, gp_sculpt)) {
+ return OPERATOR_CANCELLED;
}
- /* Set active brush */
- BKE_gpencil_brush_setactive(ts, brush);
-
- /* updates */
+ if (index < TOT_GP_EDITBRUSH_TYPES - 1) {
+ gp_sculpt->brushtype = index;
+ }
+ /* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_brush_change(wmOperatorType *ot)
+void GPENCIL_OT_sculpt_select(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Change Brush";
- ot->idname = "GPENCIL_OT_brush_change";
- ot->description = "Change active Grease Pencil drawing brush";
+ ot->name = "Select Sculpt Brush";
+ ot->idname = "GPENCIL_OT_sculpt_select";
+ ot->description = "Select a Grease Pencil sculpt brush";
/* callbacks */
- ot->invoke = gp_brush_change_invoke;
- ot->exec = gp_brush_change_exec;
- ot->poll = gp_active_brush_poll;
+ ot->exec = gp_sculpt_select_exec;
+ ot->poll = gp_add_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* gp brush to use (dynamic enum) */
- ot->prop = RNA_def_enum(ot->srna, "brush", DummyRNA_DEFAULT_items, 0, "Grease Pencil Brush", "");
- RNA_def_enum_funcs(ot->prop, ED_gpencil_brushes_enum_itemf);
+ /* properties */
+ RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of Sculpt Brush", 0, INT_MAX);
}
-/* ******************* Move Brush Up/Down ************************** */
+/*********************** Vertex Groups ***********************************/
-enum {
- GP_BRUSH_MOVE_UP = -1,
- GP_BRUSH_MOVE_DOWN = 1
-};
+static bool gpencil_vertex_group_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
+ if (ELEM(ob->mode,
+ OB_MODE_GPENCIL_EDIT,
+ OB_MODE_GPENCIL_SCULPT))
+ {
+ return true;
+ }
+ }
+ }
-static int gp_brush_move_exec(bContext *C, wmOperator *op)
+ return false;
+}
+
+static bool gpencil_vertex_group_weight_poll(bContext *C)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
+ Object *ob = CTX_data_active_object(C);
- int direction = RNA_enum_get(op->ptr, "type");
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
+ if (ob->mode == OB_MODE_GPENCIL_WEIGHT)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static int gpencil_vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
/* sanity checks */
- if (ELEM(NULL, ts, brush)) {
+ if (ELEM(NULL, ts, ob, ob->data))
return OPERATOR_CANCELLED;
- }
- /* up or down? */
- if (direction == GP_BRUSH_MOVE_UP) {
- /* up */
- BLI_remlink(&ts->gp_brushes, brush);
- BLI_insertlinkbefore(&ts->gp_brushes, brush->prev, brush);
- }
- else if (direction == GP_BRUSH_MOVE_DOWN) {
- /* down */
- BLI_remlink(&ts->gp_brushes, brush);
- BLI_insertlinkafter(&ts->gp_brushes, brush->next, brush);
- }
- else {
- BLI_assert(0);
- }
+ ED_gpencil_vgroup_assign(C, ob, ts->vgroup_weight);
/* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_brush_move(wmOperatorType *ot)
+void GPENCIL_OT_vertex_group_assign(wmOperatorType *ot)
{
- static const EnumPropertyItem slot_move[] = {
- {GP_BRUSH_MOVE_UP, "UP", 0, "Up", ""},
- {GP_BRUSH_MOVE_DOWN, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL }
- };
-
/* identifiers */
- ot->name = "Move Brush";
- ot->idname = "GPENCIL_OT_brush_move";
- ot->description = "Move the active Grease Pencil drawing brush up/down in the list";
+ ot->name = "Assign to Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_assign";
+ ot->description = "Assign the selected vertices to the active vertex group";
/* api callbacks */
- ot->exec = gp_brush_move_exec;
- ot->poll = gp_active_brush_poll;
+ ot->poll = gpencil_vertex_group_poll;
+ ot->exec = gpencil_vertex_group_assign_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- ot->prop = RNA_def_enum(ot->srna, "type", slot_move, GP_BRUSH_MOVE_UP, "Type", "");
}
-/* ******************* Brush create presets ************************** */
-
-static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
+/* remove point from vertex group */
+static int gpencil_vertex_group_remove_from_exec(bContext *C, wmOperator *UNUSED(op))
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- BKE_gpencil_brush_init_presets(ts);
+ Object *ob = CTX_data_active_object(C);
+
+ /* sanity checks */
+ if (ELEM(NULL, ob, ob->data))
+ return OPERATOR_CANCELLED;
+
+ ED_gpencil_vgroup_remove(C, ob);
/* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_brush_presets_create(wmOperatorType *ot)
+void GPENCIL_OT_vertex_group_remove_from(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 = "Remove from Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_remove_from";
+ ot->description = "Remove the selected vertices from active or all vertex group(s)";
/* api callbacks */
- ot->exec = gp_brush_presets_create_exec;
+ ot->poll = gpencil_vertex_group_poll;
+ ot->exec = gpencil_vertex_group_remove_from_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ***************** Copy Brush ************************ */
-
-static int gp_brush_copy_exec(bContext *C, wmOperator *op)
+static int gpencil_vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
{
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- /* if there's no existing container */
- if (ts == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for brush data to go");
- return OPERATOR_CANCELLED;
- }
-
- bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
- bGPDbrush *newbrush;
+ Object *ob = CTX_data_active_object(C);
/* sanity checks */
- if (ELEM(NULL, brush))
+ if (ELEM(NULL, ob, ob->data))
return OPERATOR_CANCELLED;
- /* create a brush and duplicate data */
- newbrush = BKE_gpencil_brush_addnew(ts, brush->info, true);
- newbrush->thickness = brush->thickness;
- newbrush->draw_smoothfac = brush->draw_smoothfac;
- newbrush->draw_smoothlvl = brush->draw_smoothlvl;
- newbrush->sublevel = brush->sublevel;
- newbrush->flag = brush->flag;
- newbrush->draw_sensitivity = brush->draw_sensitivity;
- newbrush->draw_strength = brush->draw_strength;
- newbrush->draw_jitter = brush->draw_jitter;
- newbrush->draw_angle = brush->draw_angle;
- newbrush->draw_angle_factor = brush->draw_angle_factor;
- newbrush->draw_random_press = brush->draw_random_press;
- newbrush->draw_random_sub = brush->draw_random_sub;
-
- /* free automatic curves created by default (replaced by copy) */
- curvemapping_free(newbrush->cur_sensitivity);
- curvemapping_free(newbrush->cur_strength);
- curvemapping_free(newbrush->cur_jitter);
-
- /* make a copy of curves */
- newbrush->cur_sensitivity = curvemapping_copy(brush->cur_sensitivity);
- newbrush->cur_strength = curvemapping_copy(brush->cur_strength);
- newbrush->cur_jitter = curvemapping_copy(brush->cur_jitter);
-
- BKE_gpencil_brush_setactive(ts, newbrush);
+ ED_gpencil_vgroup_select(C, ob);
+
/* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_brush_copy(wmOperatorType *ot)
+void GPENCIL_OT_vertex_group_select(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Copy Brush";
- ot->idname = "GPENCIL_OT_brush_copy";
- ot->description = "Copy current Grease Pencil drawing brush";
+ ot->name = "Select Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_select";
+ ot->description = "Select all the vertices assigned to the active vertex group";
- /* callbacks */
- ot->exec = gp_brush_copy_exec;
- ot->poll = gp_active_brush_poll;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_poll;
+ ot->exec = gpencil_vertex_group_select_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ***************** Select Brush ************************ */
-
-static int gp_brush_select_exec(bContext *C, wmOperator *op)
+static int gpencil_vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
{
- ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
- /* if there's no existing container */
- if (ts == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere to go");
- return OPERATOR_CANCELLED;
- }
-
- const int index = RNA_int_get(op->ptr, "index");
- bGPDbrush *brush = BLI_findlink(&ts->gp_brushes, index);
/* sanity checks */
- if (ELEM(NULL, brush)) {
+ if (ELEM(NULL, ob, ob->data))
return OPERATOR_CANCELLED;
- }
- BKE_gpencil_brush_setactive(ts, brush);
+ ED_gpencil_vgroup_deselect(C, ob);
/* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_brush_select(wmOperatorType *ot)
+void GPENCIL_OT_vertex_group_deselect(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Select Brush";
- ot->idname = "GPENCIL_OT_brush_select";
- ot->description = "Select a Grease Pencil drawing brush";
+ ot->name = "Deselect Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_deselect";
+ ot->description = "Deselect all selected vertices assigned to the active vertex group";
- /* callbacks */
- ot->exec = gp_brush_select_exec;
- ot->poll = gp_active_brush_poll;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_poll;
+ ot->exec = gpencil_vertex_group_deselect_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of Drawing Brush", 0, INT_MAX);
}
-/* ************************************************ */
-/* Palette Operators */
-
-/* ******************* Add New Palette ************************ */
-
-/* add new palette - wrapper around API */
-static int gp_palette_add_exec(bContext *C, wmOperator *op)
+/* invert */
+static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *UNUSED(op))
{
- Main *bmain = CTX_data_main(C);
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
- /* if there's no existing Grease-Pencil data there, add some */
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ /* sanity checks */
+ if (ELEM(NULL, ts, ob, ob->data))
return OPERATOR_CANCELLED;
- }
- if (*gpd_ptr == NULL)
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
- /* add new palette now */
- BKE_gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true);
+ MDeformVert *dvert;
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return OPERATOR_CANCELLED;
+
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ for (int i = 0; i < gps->totpoints; i++) {
+ dvert = &gps->dvert[i];
+ if (dvert->dw == NULL) {
+ BKE_gpencil_vgroup_add_point_weight(dvert, def_nr, 1.0f);
+ }
+ else if (dvert->dw->weight == 1.0f) {
+ BKE_gpencil_vgroup_remove_point_weight(dvert, def_nr);
+ }
+ else {
+ dvert->dw->weight = 1.0f - dvert->dw->weight;
+ }
+ }
+ }
+ CTX_DATA_END;
/* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palette_add(wmOperatorType *ot)
+void GPENCIL_OT_vertex_group_invert(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Palette";
- ot->idname = "GPENCIL_OT_palette_add";
- ot->description = "Add new Grease Pencil palette for the active Grease Pencil data-block";
+ ot->name = "Invert Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_invert";
+ ot->description = "Invert weights to the active vertex group";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_weight_poll;
+ ot->exec = gpencil_vertex_group_invert_exec;
- /* callbacks */
- ot->exec = gp_palette_add_exec;
- ot->poll = gp_add_poll;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* Remove Active Palette ************************* */
-
-static int gp_palette_remove_exec(bContext *C, wmOperator *op)
+/* smooth */
+static int gpencil_vertex_group_smooth_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ const float fac = RNA_float_get(op->ptr, "factor");
+ const int repeat = RNA_int_get(op->ptr, "repeat");
+
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
/* sanity checks */
- if (ELEM(NULL, gpd, palette))
+ if (ELEM(NULL, ts, ob, ob->data))
return OPERATOR_CANCELLED;
- if (BLI_listbase_count_at_most(&gpd->palettes, 2) < 2) {
- BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a palette, unable to delete the last one");
- return OPERATOR_CANCELLED;
- }
+ bGPDspoint *pta, *ptb, *ptc;
+ MDeformVert *dverta, *dvertb;
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return OPERATOR_CANCELLED;
- /* make the palette before this the new active palette
- * - use the one after if this is the first
- * - if this is the only palette, this naturally becomes NULL
- */
- if (palette->prev)
- BKE_gpencil_palette_setactive(gpd, palette->prev);
- else
- BKE_gpencil_palette_setactive(gpd, palette->next);
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ for (int s = 0; s < repeat; s++) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ /* previous point */
+ if (i > 0) {
+ pta = &gps->points[i - 1];
+ dverta = &gps->dvert[i - 1];
+ }
+ else {
+ pta = &gps->points[i];
+ dverta = &gps->dvert[i];
+ }
+ /* current */
+ ptb = &gps->points[i];
+ dvertb = &gps->dvert[i];
+ /* next point */
+ if (i + 1 < gps->totpoints) {
+ ptc = &gps->points[i + 1];
+ }
+ else {
+ ptc = &gps->points[i];
+ }
- /* delete the palette now... */
- BKE_gpencil_palette_delete(gpd, palette);
+ float wa = BKE_gpencil_vgroup_use_index(dverta, def_nr);
+ float wb = BKE_gpencil_vgroup_use_index(dvertb, def_nr);
+ CLAMP_MIN(wa, 0.0f);
+ CLAMP_MIN(wb, 0.0f);
+
+ /* the optimal value is the corresponding to the interpolation of the weight
+ * at the distance of point b
+ */
+ const float opfac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ const float optimal = interpf(wa, wb, opfac);
+ /* Based on influence factor, blend between original and optimal */
+ wb = interpf(wb, optimal, fac);
+ BKE_gpencil_vgroup_add_point_weight(dvertb, def_nr, wb);
+ }
+ }
+ }
+ CTX_DATA_END;
/* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palette_remove(wmOperatorType *ot)
+void GPENCIL_OT_vertex_group_smooth(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Remove palette";
- ot->idname = "GPENCIL_OT_palette_remove";
- ot->description = "Remove active Grease Pencil palette";
+ ot->name = "Smooth Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_smooth";
+ ot->description = "Smooth weights to the active vertex group";
+
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_weight_poll;
+ ot->exec = gpencil_vertex_group_smooth_exec;
+ /* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* callbacks */
- ot->exec = gp_palette_remove_exec;
- ot->poll = gp_active_palette_poll;
+ RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
}
-/* ********************** Change Palette ***************************** */
+/****************************** Join ***********************************/
-static int gp_palette_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
+/* userdata for joined_gpencil_fix_animdata_cb() */
+typedef struct tJoinGPencil_AdtFixData {
+ bGPdata *src_gpd;
+ bGPdata *tar_gpd;
+
+ GHash *names_map;
+} tJoinGPencil_AdtFixData;
+
+/* Callback to pass to BKE_fcurves_main_cb() for RNA Paths attached to each F-Curve used in the AnimData */
+static void joined_gpencil_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
{
- uiPopupMenu *pup;
- uiLayout *layout;
+ tJoinGPencil_AdtFixData *afd = (tJoinGPencil_AdtFixData *)user_data;
+ ID *src_id = &afd->src_gpd->id;
+ ID *dst_id = &afd->tar_gpd->id;
- /* call the menu, which will call this operator again, hence the canceled */
- pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
- layout = UI_popup_menu_layout(pup);
- uiItemsEnumO(layout, "GPENCIL_OT_palette_change", "palette");
- UI_popup_menu_end(C, pup);
+ GHashIterator gh_iter;
- return OPERATOR_INTERFACE;
+ /* Fix paths - If this is the target datablock, it will have some "dirty" paths */
+ if ((id == src_id) && fcu->rna_path && strstr(fcu->rna_path, "layers[")) {
+ GHASH_ITER(gh_iter, afd->names_map) {
+ const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
+ const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
+
+ /* only remap if changed; this still means there will be some waste if there aren't many drivers/keys */
+ if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) {
+ fcu->rna_path = BKE_animsys_fix_rna_path_rename(id, fcu->rna_path, "layers",
+ old_name, new_name, 0, 0, false);
+
+ /* we don't want to apply a second remapping on this F-Curve now,
+ * so stop trying to fix names names
+ */
+ break;
+ }
+ }
+ }
+
+ /* Fix driver targets */
+ if (fcu->driver) {
+ /* Fix driver references to invalid ID's */
+ for (DriverVar *dvar = fcu->driver->variables.first; dvar; dvar = dvar->next) {
+ /* only change the used targets, since the others will need fixing manually anyway */
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ /* change the ID's used... */
+ if (dtar->id == src_id) {
+ dtar->id = dst_id;
+
+ /* also check on the subtarget...
+ * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own
+ * little twists so that we know that it isn't going to clobber the wrong data
+ */
+ if (dtar->rna_path && strstr(dtar->rna_path, "layers[")) {
+ GHASH_ITER(gh_iter, afd->names_map) {
+ const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
+ const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
+
+ /* only remap if changed */
+ if (!STREQ(old_name, new_name)) {
+ if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) {
+ /* Fix up path */
+ dtar->rna_path = BKE_animsys_fix_rna_path_rename(id, dtar->rna_path, "layers",
+ old_name, new_name, 0, 0, false);
+ break; /* no need to try any more names for layer path */
+ }
+ }
+ }
+ }
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
+ }
}
-static int gp_palette_change_exec(bContext *C, wmOperator *op)
+/* join objects called from OBJECT_OT_join */
+int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- bGPDpalette *palette = NULL;
- int palette_num = RNA_enum_get(op->ptr, "palette");
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *obact = CTX_data_active_object(C);
+ bGPdata *gpd_dst = NULL;
+ bool ok = false;
+
+ /* Ensure we're in right mode and that the active object is correct */
+ if (!obact || obact->type != OB_GPENCIL)
+ return OPERATOR_CANCELLED;
- /* Get palette or create new one */
- if (palette_num == -1) {
- /* Create palette */
- palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true);
+ bGPdata *gpd = (bGPdata *)obact->data;
+ if ((!gpd) || GPENCIL_ANY_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
}
- else {
- /* Try to get palette */
- palette = BLI_findlink(&gpd->palettes, palette_num);
- if (palette == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent palette (index = %d)", palette_num);
- return OPERATOR_CANCELLED;
+ /* Ensure all rotations are applied before */
+ // XXX: Why don't we apply them here instead of warning?
+ CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
+ {
+ if (base->object->type == OB_GPENCIL) {
+ if ((base->object->rot[0] != 0) ||
+ (base->object->rot[1] != 0) ||
+ (base->object->rot[2] != 0))
+ {
+ BKE_report(op->reports, RPT_ERROR, "Apply all rotations before join objects");
+ return OPERATOR_CANCELLED;
+ }
}
}
+ CTX_DATA_END;
- /* Set active palette */
- BKE_gpencil_palette_setactive(gpd, palette);
+ CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
+ {
+ if (base->object == obact) {
+ ok = true;
+ break;
+ }
+ }
+ CTX_DATA_END;
- /* updates */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* that way the active object is always selected */
+ if (ok == false) {
+ BKE_report(op->reports, RPT_WARNING, "Active object is not a selected grease pencil");
+ return OPERATOR_CANCELLED;
+ }
- return OPERATOR_FINISHED;
-}
+ gpd_dst = obact->data;
+ Object *ob_dst = obact;
+
+ /* loop and join all data */
+ CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
+ {
+ if ((base->object->type == OB_GPENCIL) && (base->object != obact)) {
+ /* we assume that each datablock is not already used in active object */
+ if (obact->data != base->object->data) {
+ Object *ob_src = base->object;
+ bGPdata *gpd_src = base->object->data;
+
+ /* Apply all GP modifiers before */
+ for (GpencilModifierData *md = base->object->greasepencil_modifiers.first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ if (mti->bakeModifier) {
+ mti->bakeModifier(bmain, depsgraph, md, base->object);
+ }
+ }
-void GPENCIL_OT_palette_change(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Change Palette";
- ot->idname = "GPENCIL_OT_palette_change";
- ot->description = "Change active Grease Pencil palette";
+ /* copy vertex groups to the base one's */
+ int old_idx = 0;
+ for (bDeformGroup *dg = base->object->defbase.first; dg; dg = dg->next) {
+ bDeformGroup *vgroup = MEM_dupallocN(dg);
+ int idx = BLI_listbase_count(&obact->defbase);
+ defgroup_unique_name(vgroup, obact);
+ BLI_addtail(&obact->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) {
+ MDeformVert *dvert;
+ int i;
+ for (i = 0, dvert = gps->dvert; i < gps->totpoints; i++, dvert++) {
+ if ((dvert->dw) && (dvert->dw->def_nr == old_idx)) {
+ dvert->dw->def_nr = idx;
+ }
+ }
+ }
+ }
+ }
+ old_idx++;
+ }
+ if (obact->defbase.first && obact->actdef == 0)
+ obact->actdef = 1;
+
+ /* add missing materials reading source materials and checking in destination object */
+ Material ***matar = give_matarar(ob_src);
+ short *totcol = give_totcolp(ob_src);
+
+ for (short i = 0; i < *totcol; i++) {
+ Material *tmp_ma = (*matar)[i];
+ if (BKE_object_material_slot_find_index(ob_dst, tmp_ma) == 0) {
+ BKE_object_material_slot_add(bmain, ob_dst);
+ assign_material(bmain, ob_dst, tmp_ma, ob_dst->totcol, BKE_MAT_ASSIGN_EXISTING);
+ }
+ }
- /* callbacks */
- ot->invoke = gp_palette_change_invoke;
- ot->exec = gp_palette_change_exec;
- ot->poll = gp_active_palette_poll;
+ /* duplicate bGPDlayers */
+ tJoinGPencil_AdtFixData afd = {0};
+ afd.src_gpd = gpd_src;
+ afd.tar_gpd = gpd_dst;
+ afd.names_map = BLI_ghash_str_new("joined_gp_layers_map");
+
+ float imat[3][3], bmat[3][3];
+ float offset_global[3];
+ float offset_local[3];
+
+ sub_v3_v3v3(offset_global, obact->loc, base->object->obmat[3]);
+ copy_m3_m4(bmat, obact->obmat);
+ invert_m3_m3(imat, bmat);
+ mul_m3_v3(imat, offset_global);
+ mul_v3_m3v3(offset_local, imat, offset_global);
+
+
+ for (bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
+ bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src);
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+
+ /* recalculate all stroke points */
+ ED_gpencil_parent_location(depsgraph, base->object, gpd_src, gpl_src, diff_mat);
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+
+ Material *ma_src = NULL;
+ int idx;
+ for (bGPDframe *gpf = gpl_new->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ /* reasign material. Look old material and try to find in dst */
+ ma_src = give_current_material(ob_src, gps->mat_nr + 1);
+ if (ma_src != NULL) {
+ idx = BKE_object_material_slot_find_index(ob_dst, ma_src);
+ if (idx > 0) {
+ gps->mat_nr = idx - 1;
+ }
+ else {
+ gps->mat_nr = 0;
+ }
+ }
+ else {
+ gps->mat_nr = 0;
+ }
+
+ bGPDspoint *pt;
+ int i;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float mpt[3];
+ mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
+ sub_v3_v3(mpt, offset_local);
+ mul_v3_m4v3(&pt->x, diff_mat, mpt);
+ }
+ }
+ }
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* be sure name is unique in new object */
+ BLI_uniquename(&gpd_dst->layers, gpl_new, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl_new->info));
+ BLI_ghash_insert(afd.names_map, BLI_strdup(gpl_src->info), gpl_new->info);
+
+ /* add to destination datablock */
+ BLI_addtail(&gpd_dst->layers, gpl_new);
+ }
+
+ /* Fix all the animation data */
+ BKE_fcurves_main_cb(bmain, joined_gpencil_fix_animdata_cb, &afd);
+ BLI_ghash_free(afd.names_map, MEM_freeN, NULL);
+
+ /* Only copy over animdata now, after all the remapping has been done,
+ * so that we don't have to worry about ambiguities re which datablock
+ * a layer came from!
+ */
+ if (base->object->adt) {
+ if (obact->adt == NULL) {
+ /* no animdata, so just use a copy of the whole thing */
+ obact->adt = BKE_animdata_copy(bmain, base->object->adt, false, true);
+ }
+ else {
+ /* merge in data - we'll fix the drivers manually */
+ BKE_animdata_merge_copy(bmain, &obact->id, &base->object->id, ADT_MERGECOPY_KEEP_DST, false);
+ }
+ }
+
+ if (gpd_src->adt) {
+ if (gpd_dst->adt == NULL) {
+ /* no animdata, so just use a copy of the whole thing */
+ gpd_dst->adt = BKE_animdata_copy(bmain, gpd_src->adt, false, true);
+ }
+ else {
+ /* merge in data - we'll fix the drivers manually */
+ BKE_animdata_merge_copy(bmain, &gpd_dst->id, &gpd_src->id, ADT_MERGECOPY_KEEP_DST, false);
+ }
+ }
+ }
- /* gp palette to use (dynamic enum) */
- ot->prop = RNA_def_enum(ot->srna, "palette", DummyRNA_DEFAULT_items, 0, "Grease Pencil Palette", "");
- RNA_def_enum_funcs(ot->prop, ED_gpencil_palettes_enum_itemf);
+ /* Free the old object */
+ ED_object_base_free_and_unlink(bmain, scene, base->object);
+ }
+ }
+ CTX_DATA_END;
+
+ DEG_relations_tag_update(bmain); /* because we removed object(s) */
+
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+
+ return OPERATOR_FINISHED;
}
-/* ******************* Lock and hide any color non used in current layer ************************** */
+/* Color Handle operator */
+static bool gpencil_active_color_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if (ob && ob->data && (ob->type == OB_GPENCIL)) {
+ short *totcolp = give_totcolp(ob);
+ return *totcolp > 0;
+ }
+ return false;
+}
-static int gp_palette_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
+
+/* ******************* 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);
- bGPDpalette *palette;
+ Object *ob = CTX_data_active_object(C);
+ MaterialGPencilStyle *gp_style = NULL;
/* sanity checks */
if (ELEM(NULL, gpd))
return OPERATOR_CANCELLED;
- palette = BKE_gpencil_palette_getactive(gpd);
- if (ELEM(NULL, palette))
+ /* first lock and hide all colors */
+ Material *ma = NULL;
+ Material ***matar = give_matarar(ob);
+ short *totcol = give_totcolp(ob);
+ if ((totcol == 0) || (matar == NULL))
return OPERATOR_CANCELLED;
- /* first lock and hide all colors */
- for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag |= PC_COLOR_LOCKED;
- palcolor->flag |= PC_COLOR_HIDE;
+ for (short i = 0; i < *totcol; i++) {
+ ma = (*matar)[i];
+ gp_style = ma->gp_style;
+ gp_style->flag |= GP_STYLE_COLOR_LOCKED;
+ gp_style->flag |= GP_STYLE_COLOR_HIDE;
}
/* loop all selected strokes and unlock any color used in active layer */
@@ -1558,140 +2045,49 @@ static int gp_palette_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
+ gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
/* unlock/unhide color if not unlocked before */
- if (gps->palcolor != NULL) {
- gps->palcolor->flag &= ~PC_COLOR_LOCKED;
- gps->palcolor->flag &= ~PC_COLOR_HIDE;
+ if (gp_style != NULL) {
+ gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
+ gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
}
}
}
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palette_lock_layer(wmOperatorType *ot)
+void GPENCIL_OT_lock_layer(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Disable Unused Layer Colors";
- ot->idname = "GPENCIL_OT_palette_lock_layer";
+ ot->idname = "GPENCIL_OT_lock_layer";
ot->description = "Lock and hide any color not used in any layer";
/* api callbacks */
- ot->exec = gp_palette_lock_layer_exec;
+ ot->exec = gpencil_lock_layer_exec;
ot->poll = gp_active_layer_poll;
}
-/* ************************************************ */
-/* Palette Colors Operators */
-
-/* ******************* Add New Palette ************************ */
-
-/* add new palette - wrapper around API */
-static int gp_palettecolor_add_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- /* if there's no existing Grease-Pencil data there, add some */
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
- return OPERATOR_CANCELLED;
- }
- if (*gpd_ptr == NULL)
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
-
- /* verify palette */
- bGPDpalette *palette = BKE_gpencil_palette_getactive(*gpd_ptr);
- if (palette == NULL)
- palette = BKE_gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true);
-
- /* add new palette color now */
- BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_palettecolor_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Palette Color";
- ot->idname = "GPENCIL_OT_palettecolor_add";
- ot->description = "Add new Grease Pencil palette color for the active Grease Pencil data-block";
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* callbacks */
- ot->exec = gp_palettecolor_add_exec;
- ot->poll = gp_add_poll;
-}
-
-/* ******************* Remove Active Palette color ************************* */
+/* ********************** Isolate gpencil_ color **************************** */
-static int gp_palettecolor_remove_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *color = BKE_gpencil_palettecolor_getactive(palette);
-
- /* sanity checks */
- if (ELEM(NULL, gpd, palette, color))
- return OPERATOR_CANCELLED;
-
- /* make the palette color before this the new active color
- * - use the one after if this is the first
- * - if this is the only color, this naturally becomes NULL
- */
- if (color->prev)
- BKE_gpencil_palettecolor_setactive(palette, color->prev);
- else
- BKE_gpencil_palettecolor_setactive(palette, color->next);
-
- /* delete the strokes */
- BKE_gpencil_palettecolor_delete_strokes(gpd, color->info);
-
- /* delete the palette color now... */
- BKE_gpencil_palettecolor_delete(palette, color);
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ Object *ob = CTX_data_active_object(C);
+ Material *active_ma = give_current_material(ob, ob->actcol);
+ MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
+ MaterialGPencilStyle *gp_style;
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_palettecolor_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove palette color";
- ot->idname = "GPENCIL_OT_palettecolor_remove";
- ot->description = "Remove active Grease Pencil palette color";
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* callbacks */
- ot->exec = gp_palettecolor_remove_exec;
- ot->poll = gp_active_palettecolor_poll;
-}
-
-/* ********************** Isolate palette color **************************** */
-
-static int gp_isolate_palettecolor_exec(bContext *C, wmOperator *op)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *active_color = BKE_gpencil_palettecolor_getactive(palette);
- bGPDpalettecolor *palcolor;
-
- int flags = PC_COLOR_LOCKED;
+ int flags = GP_STYLE_COLOR_LOCKED;
bool isolate = false;
if (RNA_boolean_get(op->ptr, "affect_visibility"))
- flags |= PC_COLOR_HIDE;
+ flags |= GP_STYLE_COLOR_HIDE;
if (ELEM(NULL, gpd, active_color)) {
BKE_report(op->reports, RPT_ERROR, "No active color to isolate");
@@ -1699,15 +2095,20 @@ static int gp_isolate_palettecolor_exec(bContext *C, wmOperator *op)
}
/* Test whether to isolate or clear all flags */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ Material *ma = NULL;
+ Material ***matar = give_matarar(ob);
+ short *totcol = give_totcolp(ob);
+ for (short i = 0; i < *totcol; i++) {
+ ma = (*matar)[i];
/* Skip if this is the active one */
- if (palcolor == active_color)
+ if (ma == active_ma)
continue;
/* If the flags aren't set, that means that the color is
- * not alone, so we have some colors to isolate still
- */
- if ((palcolor->flag & flags) == 0) {
+ * not alone, so we have some colors to isolate still
+ */
+ gp_style = ma->gp_style;
+ if ((gp_style->flag & flags) == 0) {
isolate = true;
break;
}
@@ -1716,72 +2117,79 @@ static int gp_isolate_palettecolor_exec(bContext *C, wmOperator *op)
/* Set/Clear flags as appropriate */
if (isolate) {
/* Set flags on all "other" colors */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- if (palcolor == active_color)
+ for (short i = 0; i < *totcol; i++) {
+ ma = (*matar)[i];
+ gp_style = ma->gp_style;
+ if (gp_style == active_color)
continue;
else
- palcolor->flag |= flags;
+ gp_style->flag |= flags;
}
}
else {
/* Clear flags - Restore everything else */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag &= ~flags;
+ for (short i = 0; i < *totcol; i++) {
+ ma = (*matar)[i];
+ gp_style = ma->gp_style;
+ gp_style->flag &= ~flags;
}
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palettecolor_isolate(wmOperatorType *ot)
+void GPENCIL_OT_color_isolate(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Isolate Palette Color";
- ot->idname = "GPENCIL_OT_palettecolor_isolate";
+ ot->name = "Isolate Color";
+ ot->idname = "GPENCIL_OT_color_isolate";
ot->description = "Toggle whether the active color is the only one that is editable and/or visible";
/* callbacks */
- ot->exec = gp_isolate_palettecolor_exec;
- ot->poll = gp_active_palettecolor_poll;
+ ot->exec = gpencil_color_isolate_exec;
+ ot->poll = gpencil_active_color_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility", "In addition to toggling "
- "the editability, also affect the visibility");
+ "the editability, also affect the visibility");
}
-/* *********************** Hide Palette colors ******************************** */
+/* *********************** Hide colors ******************************** */
-static int gp_palettecolor_hide_exec(bContext *C, wmOperator *op)
+static int gpencil_color_hide_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+ Object *ob = CTX_data_active_object(C);
+ MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
bool unselected = RNA_boolean_get(op->ptr, "unselected");
- /* sanity checks */
- if (ELEM(NULL, gpd, palette, palcolor))
+ Material *ma = NULL;
+ Material ***matar = give_matarar(ob);
+ short *totcol = give_totcolp(ob);
+ if ((totcol == 0) || (matar == NULL))
return OPERATOR_CANCELLED;
if (unselected) {
- bGPDpalettecolor *color;
-
/* hide unselected */
- for (color = palette->colors.first; color; color = color->next) {
- if (color != palcolor) {
- color->flag |= PC_COLOR_HIDE;
+ MaterialGPencilStyle *color = NULL;
+ for (short i = 0; i < *totcol; i++) {
+ ma = (*matar)[i];
+ color = ma->gp_style;
+ if (active_color != color) {
+ color->flag |= GP_STYLE_COLOR_HIDE;
}
}
}
else {
/* hide selected/active */
- palcolor->flag |= PC_COLOR_HIDE;
+ active_color->flag |= GP_STYLE_COLOR_HIDE;
}
/* notifiers */
@@ -1790,18 +2198,18 @@ static int gp_palettecolor_hide_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palettecolor_hide(wmOperatorType *ot)
+void GPENCIL_OT_color_hide(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Hide Color(s)";
- ot->idname = "GPENCIL_OT_palettecolor_hide";
+ ot->idname = "GPENCIL_OT_color_hide";
ot->description = "Hide selected/unselected Grease Pencil colors";
/* callbacks */
- ot->exec = gp_palettecolor_hide_exec;
- ot->poll = gp_active_palettecolor_poll; /* NOTE: we need an active color to play with */
+ ot->exec = gpencil_color_hide_exec;
+ ot->poll = gpencil_active_color_poll; /* NOTE: we need an active color to play with */
- /* flags */
+ /* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
@@ -1810,25 +2218,23 @@ void GPENCIL_OT_palettecolor_hide(wmOperatorType *ot)
/* ********************** Show All Colors ***************************** */
-/* poll callback for showing colors */
-static bool gp_palettecolor_reveal_poll(bContext *C)
-{
- return ED_gpencil_data_get_active(C) != NULL;
-}
-
-static int gp_palettecolor_reveal_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_color_reveal_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor;
+ Object *ob = CTX_data_active_object(C);
+ Material *ma = NULL;
+ Material ***matar = give_matarar(ob);
+ short *totcol = give_totcolp(ob);
- /* sanity checks */
- if (ELEM(NULL, gpd, palette))
+ if ((totcol == 0) || (matar == NULL))
return OPERATOR_CANCELLED;
/* make all colors visible */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag &= ~PC_COLOR_HIDE;
+ MaterialGPencilStyle *gp_style = NULL;
+
+ for (short i = 0; i < *totcol; i++) {
+ ma = (*matar)[i];
+ gp_style = ma->gp_style;
+ gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
}
/* notifiers */
@@ -1837,36 +2243,41 @@ static int gp_palettecolor_reveal_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palettecolor_reveal(wmOperatorType *ot)
+void GPENCIL_OT_color_reveal(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Show All Colors";
- ot->idname = "GPENCIL_OT_palettecolor_reveal";
- ot->description = "Unhide all hidden Grease Pencil palette colors";
+ ot->idname = "GPENCIL_OT_color_reveal";
+ ot->description = "Unhide all hidden Grease Pencil gpencil_ colors";
/* callbacks */
- ot->exec = gp_palettecolor_reveal_exec;
- ot->poll = gp_palettecolor_reveal_poll;
+ ot->exec = gpencil_color_reveal_exec;
+ ot->poll = gpencil_active_color_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ***************** Lock/Unlock All Palette colors ************************ */
+/* ***************** Lock/Unlock All colors ************************ */
-static int gp_palettecolor_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_color_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor;
- /* sanity checks */
- if (ELEM(NULL, gpd, palette))
+ Object *ob = CTX_data_active_object(C);
+ Material *ma = NULL;
+ Material ***matar = give_matarar(ob);
+ short *totcol = give_totcolp(ob);
+
+ if ((totcol == 0) || (matar == NULL))
return OPERATOR_CANCELLED;
/* make all layers non-editable */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag |= PC_COLOR_LOCKED;
+ MaterialGPencilStyle *gp_style = NULL;
+
+ for (short i = 0; i < *totcol; i++) {
+ ma = (*matar)[i];
+ gp_style = ma->gp_style;
+ gp_style->flag |= GP_STYLE_COLOR_LOCKED;
}
/* notifiers */
@@ -1875,16 +2286,16 @@ static int gp_palettecolor_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palettecolor_lock_all(wmOperatorType *ot)
+void GPENCIL_OT_color_lock_all(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Lock All Colors";
- ot->idname = "GPENCIL_OT_palettecolor_lock_all";
+ ot->idname = "GPENCIL_OT_color_lock_all";
ot->description = "Lock all Grease Pencil colors to prevent them from being accidentally modified";
/* callbacks */
- ot->exec = gp_palettecolor_lock_all_exec;
- ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
+ ot->exec = gpencil_color_lock_all_exec;
+ ot->poll = gpencil_active_color_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1892,19 +2303,23 @@ void GPENCIL_OT_palettecolor_lock_all(wmOperatorType *ot)
/* -------------------------- */
-static int gp_palettecolor_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_color_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor;
+ Object *ob = CTX_data_active_object(C);
+ Material *ma = NULL;
+ Material ***matar = give_matarar(ob);
+ short *totcol = give_totcolp(ob);
- /* sanity checks */
- if (ELEM(NULL, gpd, palette))
+ if ((totcol == 0) || (matar == NULL))
return OPERATOR_CANCELLED;
/* make all layers editable again*/
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag &= ~PC_COLOR_LOCKED;
+ MaterialGPencilStyle *gp_style = NULL;
+
+ for (short i = 0; i < *totcol; i++) {
+ ma = (*matar)[i];
+ gp_style = ma->gp_style;
+ gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
}
/* notifiers */
@@ -1913,94 +2328,32 @@ static int gp_palettecolor_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palettecolor_unlock_all(wmOperatorType *ot)
+void GPENCIL_OT_color_unlock_all(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Unlock All Colors";
- ot->idname = "GPENCIL_OT_palettecolor_unlock_all";
+ ot->idname = "GPENCIL_OT_color_unlock_all";
ot->description = "Unlock all Grease Pencil colors so that they can be edited";
/* callbacks */
- ot->exec = gp_palettecolor_unlock_all_exec;
- ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
+ ot->exec = gpencil_color_unlock_all_exec;
+ ot->poll = gpencil_active_color_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* Move Color Up/Down ************************** */
-
-enum {
- GP_COLOR_MOVE_UP = -1,
- GP_COLOR_MOVE_DOWN = 1
-};
-
-static int gp_palettecolor_move_exec(bContext *C, wmOperator *op)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
-
- int direction = RNA_enum_get(op->ptr, "direction");
-
- /* sanity checks */
- if (ELEM(NULL, gpd, palette, palcolor))
- return OPERATOR_CANCELLED;
-
- /* up or down? */
- if (direction == GP_COLOR_MOVE_UP) {
- /* up */
- BLI_remlink(&palette->colors, palcolor);
- BLI_insertlinkbefore(&palette->colors, palcolor->prev, palcolor);
- }
- else if (direction == GP_COLOR_MOVE_DOWN) {
- /* down */
- BLI_remlink(&palette->colors, palcolor);
- BLI_insertlinkafter(&palette->colors, palcolor->next, palcolor);
- }
- else {
- BLI_assert(0);
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_palettecolor_move(wmOperatorType *ot)
-{
- static const EnumPropertyItem slot_move[] = {
- {GP_COLOR_MOVE_UP, "UP", 0, "Up", ""},
- {GP_COLOR_MOVE_DOWN, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Move Palette color";
- ot->idname = "GPENCIL_OT_palettecolor_move";
- ot->description = "Move the active Grease Pencil palette color up/down in the list";
- /* api callbacks */
- ot->exec = gp_palettecolor_move_exec;
- ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
+/* ***************** Select all strokes using color ************************ */
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_COLOR_MOVE_UP, "Direction", "");
-}
-
-/* ***************** Select all strokes using Palette color ************************ */
-
-static int gp_palettecolor_select_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_color_select_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+ Object *ob = CTX_data_active_object(C);
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol);
/* sanity checks */
- if (ELEM(NULL, gpd, palette, palcolor))
+ if (ELEM(NULL, gpd, gp_style))
return OPERATOR_CANCELLED;
/* read all strokes and select*/
@@ -2013,11 +2366,11 @@ static int gp_palettecolor_select_exec(bContext *C, wmOperator *UNUSED(op))
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
continue;
/* select */
- if (strcmp(palcolor->info, gps->colorname) == 0) {
+ if (ob->actcol == gps->mat_nr) {
bGPDspoint *pt;
int i;
@@ -2035,56 +2388,16 @@ static int gp_palettecolor_select_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palettecolor_select(wmOperatorType *ot)
+void GPENCIL_OT_color_select(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Color";
- ot->idname = "GPENCIL_OT_palettecolor_select";
+ ot->idname = "GPENCIL_OT_color_select";
ot->description = "Select all Grease Pencil strokes using current color";
/* callbacks */
- ot->exec = gp_palettecolor_select_exec;
- ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ***************** Copy Palette color ************************ */
-
-static int gp_palettecolor_copy_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
- bGPDpalettecolor *newcolor;
-
- /* sanity checks */
- if (ELEM(NULL, gpd, palette, palcolor))
- return OPERATOR_CANCELLED;
-
- /* create a new color and duplicate data */
- newcolor = BKE_gpencil_palettecolor_addnew(palette, palcolor->info, true);
- copy_v4_v4(newcolor->color, palcolor->color);
- copy_v4_v4(newcolor->fill, palcolor->fill);
- newcolor->flag = palcolor->flag;
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_palettecolor_copy(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Copy Color";
- ot->idname = "GPENCIL_OT_palettecolor_copy";
- ot->description = "Copy current Grease Pencil palette color";
-
- /* callbacks */
- ot->exec = gp_palettecolor_copy_exec;
- ot->poll = gp_active_palettecolor_poll;
+ ot->exec = gpencil_color_select_exec;
+ ot->poll = gpencil_active_color_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index ec67b2da161..4264645b52e 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -47,6 +47,7 @@
#include "BLT_translation.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -54,12 +55,19 @@
#include "DNA_view3d_types.h"
#include "DNA_gpencil_types.h"
+#include "BKE_main.h"
#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_brush.h"
#include "BKE_gpencil.h"
+#include "BKE_paint.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -80,31 +88,70 @@
#include "ED_space_api.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "gpencil_intern.h"
/* ************************************************ */
/* Stroke Edit Mode Management */
-
static bool gpencil_editmode_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_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *op)
{
+ const int back = RNA_boolean_get(op->ptr, "back");
+ Depsgraph *depsgraph = CTX_data_depsgraph(C); \
bGPdata *gpd = ED_gpencil_data_get_active(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)
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active GP data");
return OPERATOR_CANCELLED;
+ }
/* Just toggle editmode flag... */
gpd->flag ^= GP_DATA_STROKE_EDITMODE;
/* recalculate parent matrix */
if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
- ED_gpencil_reset_layers_parent(gpd);
+ ED_gpencil_reset_layers_parent(depsgraph, ob, gpd);
+ }
+ /* set mode */
+ if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ mode = OB_MODE_GPENCIL_EDIT;
+ }
+ else {
+ mode = OB_MODE_OBJECT;
+ }
+
+ if (is_object) {
+ /* try to back previous mode */
+ if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_EDITMODE) == 0) && (back == 1)) {
+ mode = ob->restore_mode;
+ }
+ ob->restore_mode = ob->mode;
+ ob->mode = mode;
}
+ /* setup other modes */
+ ED_gpencil_setup_modes(C, gpd, mode);
+ /* set cache as dirty */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
@@ -114,6 +161,8 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void GPENCIL_OT_editmode_toggle(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Strokes Edit Mode Toggle";
ot->idname = "GPENCIL_OT_editmode_toggle";
@@ -125,6 +174,259 @@ void GPENCIL_OT_editmode_toggle(wmOperatorType *ot)
/* 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 Paint Mode Management */
+
+static bool gpencil_paintmode_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_paintmode_toggle_exec(bContext *C, wmOperator *op)
+{
+ const bool back = RNA_boolean_get(op->ptr, "back");
+
+ 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_PAINTMODE;
+ /* set mode */
+ if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
+ mode = OB_MODE_GPENCIL_PAINT;
+ }
+ else {
+ mode = OB_MODE_OBJECT;
+ }
+
+ if (is_object) {
+ /* try to back previous mode */
+ if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0) && (back == 1)) {
+ mode = ob->restore_mode;
+ }
+ ob->restore_mode = ob->mode;
+ ob->mode = mode;
+ }
+
+ /* be sure we have brushes */
+ Paint *paint = BKE_brush_get_gpencil_paint(ts);
+ /* if not exist, create a new one */
+ if (paint->brush == NULL) {
+ BKE_brush_gpencil_presets(C);
+ }
+
+ /* setup other modes */
+ ED_gpencil_setup_modes(C, gpd, mode);
+ /* set cache as dirty */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_paintmode_toggle(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Strokes Paint Mode Toggle";
+ ot->idname = "GPENCIL_OT_paintmode_toggle";
+ ot->description = "Enter/Exit paint mode for Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gpencil_paintmode_toggle_exec;
+ ot->poll = gpencil_paintmode_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 Sculpt Mode Management */
+
+static bool gpencil_sculptmode_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_sculptmode_toggle_exec(bContext *C, wmOperator *op)
+{
+ const bool back = RNA_boolean_get(op->ptr, "back");
+
+ bGPdata *gpd = ED_gpencil_data_get_active(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 sculptmode flag... */
+ gpd->flag ^= GP_DATA_STROKE_SCULPTMODE;
+ /* set mode */
+ if (gpd->flag & GP_DATA_STROKE_SCULPTMODE) {
+ mode = OB_MODE_GPENCIL_SCULPT;
+ }
+ else {
+ mode = OB_MODE_OBJECT;
+ }
+
+ if (is_object) {
+ /* try to back previous mode */
+ if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_SCULPTMODE) == 0) && (back == 1)) {
+ mode = ob->restore_mode;
+ }
+ ob->restore_mode = ob->mode;
+ ob->mode = mode;
+ }
+
+ /* setup other modes */
+ ED_gpencil_setup_modes(C, gpd, mode);
+ /* set cache as dirty */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_sculptmode_toggle(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Strokes Sculpt Mode Toggle";
+ ot->idname = "GPENCIL_OT_sculptmode_toggle";
+ ot->description = "Enter/Exit sculpt mode for Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gpencil_sculptmode_toggle_exec;
+ ot->poll = gpencil_sculptmode_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 Weight Paint Mode Management */
+
+static bool gpencil_weightmode_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_weightmode_toggle_exec(bContext *C, wmOperator *op)
+{
+ const bool back = RNA_boolean_get(op->ptr, "back");
+
+ bGPdata *gpd = ED_gpencil_data_get_active(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 weightmode flag... */
+ gpd->flag ^= GP_DATA_STROKE_WEIGHTMODE;
+ /* set mode */
+ if (gpd->flag & GP_DATA_STROKE_WEIGHTMODE) {
+ mode = OB_MODE_GPENCIL_WEIGHT;
+ }
+ else {
+ mode = OB_MODE_OBJECT;
+ }
+
+ if (is_object) {
+ /* try to back previous mode */
+ if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && (back == 1)) {
+ mode = ob->restore_mode;
+ }
+ ob->restore_mode = ob->mode;
+ ob->mode = mode;
+ }
+
+ /* setup other modes */
+ ED_gpencil_setup_modes(C, gpd, mode);
+ /* set cache as dirty */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_weightmode_toggle(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Strokes Weight Mode Toggle";
+ ot->idname = "GPENCIL_OT_weightmode_toggle";
+ ot->description = "Enter/Exit weight paint mode for Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gpencil_weightmode_toggle_exec;
+ ot->poll = gpencil_weightmode_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);
}
/* ************************************************ */
@@ -137,21 +439,30 @@ static bool gp_stroke_edit_poll(bContext *C)
return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
}
+/* poll callback to verify edit mode in 3D view only */
+static bool gp_strokes_edit3d_poll(bContext *C)
+{
+ /* 2 Requirements:
+ * - 1) Editable GP data
+ * - 2) 3D View only
+ */
+ return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C));
+}
+
/* ************ Stroke Hide selection Toggle ************** */
static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- if (ts == NULL)
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d == NULL)
return OPERATOR_CANCELLED;
/* Just toggle alpha... */
- if (ts->gp_sculpt.alpha > 0.0f) {
- ts->gp_sculpt.alpha = 0.0f;
+ if (v3d->vertex_opacity > 0.0f) {
+ v3d->vertex_opacity = 0.0f;
}
else {
- ts->gp_sculpt.alpha = 1.0f;
+ v3d->vertex_opacity = 1.0f;
}
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
@@ -176,6 +487,44 @@ void GPENCIL_OT_selection_opacity_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
}
+/* toggle multi edit strokes support */
+static int gpencil_multiedit_toggle_exec(bContext *C, wmOperator *op)
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ const bool lines = RNA_boolean_get(op->ptr, "lines");
+
+ /* Just toggle value */
+ if (lines == 0) {
+ v3d->flag3 ^= V3D_GP_SHOW_EDIT_LINES;
+ }
+ else {
+ v3d->flag3 ^= V3D_GP_SHOW_MULTIEDIT_LINES;
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_multiedit_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Edit Lines Toggle";
+ ot->idname = "GPENCIL_OT_multiedit_toggle";
+ ot->description = "Enable/disable edit lines support";
+
+ /* callbacks */
+ ot->exec = gpencil_multiedit_toggle_exec;
+ ot->poll = gp_stroke_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "toggle_visibility", 0, "Toggle Visibility Only", "Toggle visibility of edit lines only");
+}
+
/* ************** Duplicate Selected Strokes **************** */
/* Make copies of selected point segments in a selected stroke */
@@ -220,7 +569,7 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, co
/* make a stupid copy first of the entire stroke (to get the flags too) */
gpsd = MEM_dupallocN(gps);
- BLI_strncpy(gpsd->tmp_layerinfo, layername, sizeof(gpsd->tmp_layerinfo)); /* saves original layer name */
+ BLI_strncpy(gpsd->runtime.tmp_layerinfo, layername, sizeof(gpsd->runtime.tmp_layerinfo)); /* saves original layer name */
/* initialize triangle memory - will be calculated on next redraw */
gpsd->triangles = NULL;
@@ -232,6 +581,20 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, co
memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len);
gpsd->totpoints = len;
+ if (gps->dvert != NULL) {
+ gpsd->dvert = MEM_callocN(sizeof(MDeformVert) * len, "gps stroke weights copy");
+ memcpy(gpsd->dvert, gps->dvert + start_idx, sizeof(MDeformVert) * len);
+
+ /* Copy weights */
+ int e = start_idx;
+ for (int j = 0; j < gpsd->totpoints; j++) {
+ MDeformVert *dvert_dst = &gps->dvert[e];
+ MDeformVert *dvert_src = &gps->dvert[j];
+ dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ e++;
+ }
+ }
+
/* add to temp buffer */
gpsd->next = gpsd->prev = NULL;
BLI_addtail(new_strokes, gpsd);
@@ -252,6 +615,11 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
+ return OPERATOR_CANCELLED;
+ }
+
/* for each visible (and editable) layer's selected strokes,
* copy the strokes into a temporary buffer, then append
* once all done
@@ -279,8 +647,12 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
/* make direct copies of the stroke and its points */
gpsd = MEM_dupallocN(gps);
- BLI_strncpy(gpsd->tmp_layerinfo, gpl->info, sizeof(gpsd->tmp_layerinfo));
+ 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_CACHES;
@@ -309,6 +681,7 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -342,7 +715,7 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot)
/* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */
ListBase gp_strokes_copypastebuf = {NULL, NULL};
-/* Hash for hanging on to all the palette colors used by strokes in the buffer
+/* Hash for hanging on to all the colors used by strokes in the buffer
*
* This is needed to prevent dangling and unsafe pointers when pasting across datablocks,
* or after a color used by a stroke in the buffer gets deleted (via user action or undo).
@@ -354,11 +727,11 @@ void ED_gpencil_strokes_copybuf_free(void)
{
bGPDstroke *gps, *gpsn;
- /* Free the palettes buffer
- * NOTE: This is done before the strokes so that the name ptrs (keys) are still safe
+ /* Free the colors buffer
+ * NOTE: This is done before the strokes so that the ptrs are still safe
*/
if (gp_strokes_copypastebuf_colors) {
- BLI_ghash_free(gp_strokes_copypastebuf_colors, NULL, MEM_freeN);
+ BLI_ghash_free(gp_strokes_copypastebuf_colors, NULL, NULL);
gp_strokes_copypastebuf_colors = NULL;
}
@@ -366,8 +739,15 @@ void ED_gpencil_strokes_copybuf_free(void)
for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) {
gpsn = gps->next;
- if (gps->points) MEM_freeN(gps->points);
- if (gps->triangles) MEM_freeN(gps->triangles);
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+
+ MEM_SAFE_FREE(gps->triangles);
BLI_freelinkN(&gp_strokes_copypastebuf, gps);
}
@@ -378,38 +758,26 @@ void ED_gpencil_strokes_copybuf_free(void)
/* Ensure that destination datablock has all the colours the pasted strokes need
* Helper function for copy-pasting strokes
*/
-GHash *gp_copybuf_validate_colormap(bGPdata *gpd)
+GHash *gp_copybuf_validate_colormap(bContext *C)
{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
GHash *new_colors = BLI_ghash_str_new("GPencil Paste Dst Colors");
GHashIterator gh_iter;
- /* If there's no active palette yet (i.e. new datablock), add one */
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- if (palette == NULL) {
- palette = BKE_gpencil_palette_addnew(gpd, "Pasted Palette", true);
- }
-
- /* For each color, figure out what to map to... */
+ /* For each color, check if exist and add if not */
GHASH_ITER(gh_iter, gp_strokes_copypastebuf_colors) {
- bGPDpalettecolor *palcolor;
- char *name = BLI_ghashIterator_getKey(&gh_iter);
-
- /* Look for existing color to map to */
- /* XXX: What to do if same name but different color? Behaviour here should depend on a property? */
- palcolor = BKE_gpencil_palettecolor_getbyname(palette, name);
- if (palcolor == NULL) {
- /* Doesn't Exist - Create new matching color for this palette */
- /* XXX: This still doesn't fix the pasting across file boundaries problem... */
- bGPDpalettecolor *src_color = BLI_ghashIterator_getValue(&gh_iter);
- palcolor = MEM_dupallocN(src_color);
- BLI_addtail(&palette->colors, palcolor);
+ int *key = BLI_ghashIterator_getKey(&gh_iter);
+ Material *ma = BLI_ghashIterator_getValue(&gh_iter);
- BLI_uniquename(&palette->colors, palcolor, DATA_("GP Color"), '.', offsetof(bGPDpalettecolor, info), sizeof(palcolor->info));
+ if (BKE_object_material_slot_find_index(ob, ma) == 0) {
+ BKE_object_material_slot_add(bmain, ob);
+ assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_EXISTING);
}
/* Store this mapping (for use later when pasting) */
- BLI_ghash_insert(new_colors, name, palcolor);
+ BLI_ghash_insert(new_colors, key, ma);
}
return new_colors;
@@ -420,6 +788,7 @@ GHash *gp_copybuf_validate_colormap(bGPdata *gpd)
static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
{
+ Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
if (gpd == NULL) {
@@ -427,6 +796,11 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
+ return OPERATOR_CANCELLED;
+ }
+
/* clear the buffer first */
ED_gpencil_strokes_copybuf_free();
@@ -455,8 +829,12 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
/* make direct copies of the stroke and its points */
gpsd = MEM_dupallocN(gps);
- BLI_strncpy(gpsd->tmp_layerinfo, gpl->info, sizeof(gpsd->tmp_layerinfo)); /* saves original layer name */
+ BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo)); /* saves original layer name */
gpsd->points = MEM_dupallocN(gps->points);
+ if (gps->dvert != NULL) {
+ gpsd->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, gpsd);
+ }
/* triangles cache - will be recalculated on next redraw */
gpsd->flag |= GP_STROKE_RECALC_CACHES;
@@ -476,17 +854,16 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- /* Build up hash of colors used in these strokes, making copies of these to protect against dangling pointers */
+ /* Build up hash of material colors used in these strokes */
if (gp_strokes_copypastebuf.first) {
gp_strokes_copypastebuf_colors = BLI_ghash_str_new("GPencil CopyBuf Colors");
-
+ Material *ma = NULL;
for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
if (ED_gpencil_stroke_can_use(C, gps)) {
- if (BLI_ghash_haskey(gp_strokes_copypastebuf_colors, gps->colorname) == false) {
- bGPDpalettecolor *color = MEM_dupallocN(gps->palcolor);
-
- BLI_ghash_insert(gp_strokes_copypastebuf_colors, gps->colorname, color);
- gps->palcolor = color;
+ ma = give_current_material(ob, gps->mat_nr + 1);
+ if (BLI_ghash_haskey(gp_strokes_copypastebuf_colors, &gps->mat_nr) == false)
+ {
+ BLI_ghash_insert(gp_strokes_copypastebuf_colors, &gps->mat_nr, ma);
}
}
}
@@ -534,9 +911,11 @@ typedef enum eGP_PasteMode {
static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ 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 */
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
bGPDframe *gpf;
eGP_PasteMode type = RNA_enum_get(op->ptr, "type");
@@ -547,6 +926,10 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
return OPERATOR_CANCELLED;
}
+ else if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
+ return OPERATOR_CANCELLED;
+ }
else if (BLI_listbase_is_empty(&gp_strokes_copypastebuf)) {
BKE_report(op->reports, RPT_ERROR, "No strokes to paste, select and copy some points before trying again");
return OPERATOR_CANCELLED;
@@ -599,14 +982,14 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* Ensure that all the necessary colors exist */
- new_colors = gp_copybuf_validate_colormap(gpd);
+ 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) {
if (ED_gpencil_stroke_can_use(C, gps)) {
/* Need to verify if layer exists */
if (type != GP_COPY_MERGE) {
- gpl = BLI_findstring(&gpd->layers, gps->tmp_layerinfo, offsetof(bGPDlayer, info));
+ 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);
@@ -618,28 +1001,33 @@ 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, true);
+ gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, true);
if (gpf) {
/* Create new stroke */
bGPDstroke *new_stroke = MEM_dupallocN(gps);
- new_stroke->tmp_layerinfo[0] = '\0';
+ new_stroke->runtime.tmp_layerinfo[0] = '\0';
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_CACHES;
new_stroke->triangles = NULL;
new_stroke->next = new_stroke->prev = NULL;
BLI_addtail(&gpf->strokes, new_stroke);
- /* Fix color references */
- BLI_assert(new_stroke->colorname[0] != '\0');
- new_stroke->palcolor = BLI_ghash_lookup(new_colors, new_stroke->colorname);
-
- BLI_assert(new_stroke->palcolor != NULL);
- BLI_strncpy(new_stroke->colorname, new_stroke->palcolor->info, sizeof(new_stroke->colorname));
+ /* Remap material */
+ Material *ma = BLI_ghash_lookup(new_colors, &new_stroke->mat_nr);
+ if ((ma) && (BKE_object_material_slot_find_index(ob, ma) > 0)) {
+ gps->mat_nr = BKE_object_material_slot_find_index(ob, ma) - 1;
+ CLAMP_MIN(gps->mat_nr, 0);
+ }
+ else {
+ gps->mat_nr = 0; /* only if the color is not found */
+ }
- /*new_stroke->flag |= GP_STROKE_RECALC_COLOR; */
}
}
}
@@ -648,6 +1036,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
BLI_ghash_free(new_colors, NULL, NULL);
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -697,10 +1086,17 @@ static int gp_move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *U
static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = CTX_data_gpencil_data(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
bGPDlayer *target_layer = NULL;
ListBase strokes = {NULL, NULL};
int layer_num = RNA_enum_get(op->ptr, "layer");
+ if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
+ return OPERATOR_CANCELLED;
+ }
+
/* Get layer or create new one */
if (layer_num == -1) {
/* Create layer */
@@ -748,14 +1144,14 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
/* Paste them all in one go */
if (strokes.first) {
- Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = BKE_gpencil_layer_getframe(target_layer, CFRA, true);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(target_layer, cfra_eval, true);
BLI_movelisttolist(&gpf->strokes, &strokes);
BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL));
}
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -804,8 +1200,10 @@ static bool UNUSED_FUNCTION(gp_blank_frame_add_poll)(bContext *C)
static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
bGPDlayer *active_gpl = BKE_gpencil_layer_getactive(gpd);
const bool all_layers = RNA_boolean_get(op->ptr, "all_layers");
@@ -826,7 +1224,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_find_frame(gpl, cfra_eval);
if (gpf) {
/* Shunt all frames after (and including) the existing one later by 1-frame */
for (; gpf; gpf = gpf->next) {
@@ -835,11 +1233,12 @@ 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_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
}
CTX_DATA_END;
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -876,10 +1275,13 @@ static bool gp_actframe_delete_poll(bContext *C)
/* delete active frame - wrapper around API calls */
static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
+
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0);
/* if there's no existing Grease-Pencil data there, add some */
if (gpd == NULL) {
@@ -895,6 +1297,7 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
BKE_gpencil_layer_delframe(gpl, gpf);
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -928,13 +1331,16 @@ static bool gp_actframe_delete_all_poll(bContext *C)
static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
bool success = false;
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, 0);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0);
if (gpf == NULL)
continue;
@@ -949,6 +1355,7 @@ static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op)
/* updates */
if (success) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -983,43 +1390,69 @@ typedef enum eGP_DeleteMode {
GP_DELETEOP_FRAME = 2,
} eGP_DeleteMode;
+typedef enum eGP_DissolveMode {
+ /* dissolve all selected points */
+ GP_DISSOLVE_POINTS = 0,
+ /* dissolve between selected points */
+ GP_DISSOLVE_BETWEEN = 1,
+ /* dissolve unselected points */
+ GP_DISSOLVE_UNSELECT = 2,
+} eGP_DissolveMode;
+
/* ----------------------------------- */
/* Delete selected strokes */
static int gp_delete_selected_strokes(bContext *C)
{
bool changed = false;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps, *gpsn;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
- if (gpf == NULL)
- continue;
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ bGPDstroke *gps, *gpsn;
- /* simply delete strokes which are selected */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ if (gpf == NULL)
+ continue;
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
+ /* simply delete strokes which are selected */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
- /* free stroke if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- /* free stroke memory arrays, then stroke itself */
- if (gps->points) MEM_freeN(gps->points);
- if (gps->triangles) MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
- changed = true;
+ /* free stroke if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* free stroke memory arrays, then stroke itself */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ MEM_SAFE_FREE(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+
+ changed = true;
+ }
+ }
}
}
}
CTX_DATA_END;
if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -1031,88 +1464,238 @@ static int gp_delete_selected_strokes(bContext *C)
/* ----------------------------------- */
/* Delete selected points but keep the stroke */
-static int gp_dissolve_selected_points(bContext *C)
+static int gp_dissolve_selected_points(bContext *C, eGP_DissolveMode mode)
{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
bool changed = false;
+ int first = 0;
+ int last = 0;
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps, *gpsn;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
- if (gpf == NULL)
- continue;
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- /* simply delete points from selected strokes
- * NOTE: we may still have to remove the stroke if it ends up having no points!
- */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ bGPDstroke *gps, *gpsn;
- /* 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(gpl, gps) == false)
- continue;
+ if (gpf == NULL)
+ continue;
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
+ /* simply delete points from selected strokes
+ * NOTE: we may still have to remove the stroke if it ends up having no points!
+ */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
+ continue;
+
+ /* the stroke must have at least one point selected for any operator */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ MDeformVert *dvert = NULL;
+ int i;
+
+ int tot = gps->totpoints; /* number of points in new buffer */
+
+ /* first pass: count points to remove */
+ switch (mode) {
+ case GP_DISSOLVE_POINTS:
+ /* Count how many points are selected (i.e. how many to remove) */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* selected point - one of the points to remove */
+ tot--;
+ }
+ }
+ break;
+ case GP_DISSOLVE_BETWEEN:
+ /* need to find first and last point selected */
+ first = -1;
+ last = 0;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (first < 0) {
+ first = i;
+ }
+ last = i;
+ }
+ }
+ /* count unselected points in the range */
+ for (i = first, pt = gps->points + first; i < last; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) == 0) {
+ tot--;
+ }
+ }
+ break;
+ case GP_DISSOLVE_UNSELECT:
+ /* count number of unselected points */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) == 0) {
+ tot--;
+ }
+ }
+ break;
+ default:
+ return false;
+ break;
+ }
- int tot = gps->totpoints; /* number of points in new buffer */
+ /* if no points are left, we simply delete the entire stroke */
+ if (tot <= 0) {
+ /* remove the entire stroke */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ if (gps->triangles) {
+ MEM_freeN(gps->triangles);
+ }
+ BLI_freelinkN(&gpf->strokes, gps);
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ }
+ else {
+ /* just copy all points to keep into a smaller buffer */
+ bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy");
+ bGPDspoint *npt = new_points;
- /* First Pass: Count how many points are selected (i.e. how many to remove) */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- /* selected point - one of the points to remove */
- tot--;
- }
- }
+ MDeformVert *new_dvert = NULL;
+ MDeformVert *ndvert = NULL;
- /* if no points are left, we simply delete the entire stroke */
- if (tot <= 0) {
- /* remove the entire stroke */
- MEM_freeN(gps->points);
- if (gps->triangles) {
- MEM_freeN(gps->triangles);
- }
- BLI_freelinkN(&gpf->strokes, gps);
- }
- else {
- /* just copy all unselected into a smaller buffer */
- bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy");
- bGPDspoint *npt = new_points;
+ if (gps->dvert != NULL) {
+ new_dvert = MEM_callocN(sizeof(MDeformVert) * tot, "new gp stroke weights copy");
+ ndvert = new_dvert;
+ }
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if ((pt->flag & GP_SPOINT_SELECT) == 0) {
- *npt = *pt;
- npt++;
- }
- }
+ switch (mode) {
+ case GP_DISSOLVE_POINTS:
+ (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) == 0) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+ }
+ break;
+ case GP_DISSOLVE_BETWEEN:
+ /* copy first segment */
+ (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
+ for (i = 0, pt = gps->points; i < first; i++, pt++) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+ /* copy segment (selected points) */
+ (gps->dvert != NULL) ? dvert = gps->dvert + first : NULL;
+ for (i = first, pt = gps->points + first; i < last; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+ }
+ /* copy last segment */
+ (gps->dvert != NULL) ? dvert = gps->dvert + last : NULL;
+ for (i = last, pt = gps->points + last; i < gps->totpoints; i++, pt++) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+
+ break;
+ case GP_DISSOLVE_UNSELECT:
+ /* copy any selected point */
+ (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+ }
+ break;
+ }
- /* free the old buffer */
- MEM_freeN(gps->points);
+ /* free the old buffer */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
- /* save the new buffer */
- gps->points = new_points;
- gps->totpoints = tot;
+ /* save the new buffer */
+ gps->points = new_points;
+ gps->dvert = new_dvert;
+ gps->totpoints = tot;
- /* triangles cache needs to be recalculated */
- gps->flag |= GP_STROKE_RECALC_CACHES;
- gps->tot_triangles = 0;
+ /* triangles cache needs to be recalculated */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
- /* deselect the stroke, since none of its selected points will still be selected */
- gps->flag &= ~GP_STROKE_SELECT;
- }
+ /* deselect the stroke, since none of its selected points will still be selected */
+ gps->flag &= ~GP_STROKE_SELECT;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
- changed = true;
+ changed = true;
+ }
+ }
}
}
}
CTX_DATA_END;
if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -1146,17 +1729,17 @@ typedef struct tGPDeleteIsland {
* becomes much less
* 2) Each island gets converted to a new stroke
*/
-void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags)
+void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke,
+ int tag_flags, bool select)
{
tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands");
bool in_island = false;
int num_islands = 0;
- bGPDspoint *pt;
- int i;
/* First Pass: Identify start/end of islands */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ bGPDspoint *pt = gps->points;
+ for (int i = 0; i < gps->totpoints; i++, pt++) {
if (pt->flag & tag_flags) {
/* selected - stop accumulating to island */
in_island = false;
@@ -1198,11 +1781,26 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke
/* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */
new_stroke->totpoints = island->end_idx - island->start_idx + 1;
- new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment");
- /* Copy over the relevant points */
+ /* Copy over the relevant point data */
+ new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment");
memcpy(new_stroke->points, gps->points + island->start_idx, sizeof(bGPDspoint) * new_stroke->totpoints);
-
+
+ /* Copy over vertex weight data (if available) */
+ if (new_stroke->dvert != NULL) {
+ /* Copy over the relevant vertex-weight points */
+ new_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints, "gp delete stroke fragment weight");
+ memcpy(new_stroke->dvert, gps->dvert + island->start_idx, sizeof(MDeformVert) * new_stroke->totpoints);
+
+ /* Copy weights */
+ int e = island->start_idx;
+ for (int i = 0; i < new_stroke->totpoints; i++) {
+ MDeformVert *dvert_dst = &gps->dvert[e];
+ MDeformVert *dvert_src = &new_stroke->dvert[i];
+ dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ e++;
+ }
+ }
/* Each island corresponds to a new stroke. We must adjust the
* timings of these new strokes:
@@ -1222,6 +1820,11 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke
pts = new_stroke->points;
for (j = 0; j < new_stroke->totpoints; j++, pts++) {
pts->time -= delta;
+ /* set flag for select again later */
+ if (select == true) {
+ pts->flag &= ~GP_SPOINT_SELECT;
+ pts->flag |= GP_SPOINT_TAG;
+ }
}
}
@@ -1239,53 +1842,70 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke
MEM_freeN(islands);
/* Delete the old stroke */
- MEM_freeN(gps->points);
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
if (gps->triangles) {
MEM_freeN(gps->triangles);
}
BLI_freelinkN(&gpf->strokes, gps);
}
-
/* Split selected strokes into segments, splitting on selected points */
static int gp_delete_selected_points(bContext *C)
{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
bool changed = false;
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps, *gpsn;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
- if (gpf == NULL)
- continue;
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ bGPDstroke *gps, *gpsn;
- /* simply delete strokes which are selected */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ if (gpf == NULL)
+ continue;
- /* 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(gpl, gps) == false)
- continue;
+ /* simply delete strokes which are selected */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
+ continue;
- if (gps->flag & GP_STROKE_SELECT) {
- /* deselect old stroke, since it will be used as template for the new strokes */
- 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);
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* deselect old stroke, since it will be used as template for the new strokes */
+ gps->flag &= ~GP_STROKE_SELECT;
- changed = true;
+ /* delete unwanted points by splitting stroke into several smaller ones */
+ gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false);
+
+ changed = true;
+ }
+ }
}
}
}
CTX_DATA_END;
if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -1294,6 +1914,12 @@ static int gp_delete_selected_points(bContext *C)
}
}
+/* simple wrapper to external call */
+int gp_delete_selected_point_wrap(bContext *C)
+{
+ return gp_delete_selected_points(C);
+}
+
/* ----------------------------------- */
static int gp_delete_exec(bContext *C, wmOperator *op)
@@ -1344,24 +1970,37 @@ void GPENCIL_OT_delete(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_delete_types, 0, "Type", "Method used for deleting Grease Pencil data");
}
-static int gp_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
+static int gp_dissolve_exec(bContext *C, wmOperator *op)
{
- return gp_dissolve_selected_points(C);
+ eGP_DissolveMode mode = RNA_enum_get(op->ptr, "type");
+
+ return gp_dissolve_selected_points(C, mode);
}
void GPENCIL_OT_dissolve(wmOperatorType *ot)
{
+ static EnumPropertyItem prop_gpencil_dissolve_types[] = {
+ { GP_DISSOLVE_POINTS, "POINTS", 0, "Dissolve", "Dissolve selected points" },
+ { GP_DISSOLVE_BETWEEN, "BETWEEN", 0, "Dissolve Between", "Dissolve points between selected points" },
+ { GP_DISSOLVE_UNSELECT, "UNSELECT", 0, "Dissolve Unselect", "Dissolve all unselected points" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
/* identifiers */
ot->name = "Dissolve";
ot->idname = "GPENCIL_OT_dissolve";
ot->description = "Delete selected points without splitting strokes";
/* callbacks */
+ ot->invoke = WM_menu_invoke;
ot->exec = gp_dissolve_exec;
ot->poll = gp_stroke_edit_poll;
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* props */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_dissolve_types, 0, "Type", "Method used for disolving Stroke points");
}
/* ****************** Snapping - Strokes <-> Cursor ************************ */
@@ -1384,6 +2023,8 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
RegionView3D *rv3d = CTX_wm_region_data(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C); \
+ Object *obact = CTX_data_active_object(C);
const float gridf = rv3d->gridview;
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
@@ -1392,10 +2033,8 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
bGPDframe *gpf = gpl->actframe;
float diff_mat[4][4];
- /* calculate difference matrix if parent object */
- if (gpl->parent != NULL) {
- ED_gpencil_parent_location(gpl, diff_mat);
- }
+ /* calculate difference matrix object */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
bGPDspoint *pt;
@@ -1405,37 +2044,32 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false)
continue;
// TODO: if entire stroke is selected, offset entire stroke by same amount?
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
/* only if point is selected */
if (pt->flag & GP_SPOINT_SELECT) {
- if (gpl->parent == NULL) {
- pt->x = gridf * floorf(0.5f + pt->x / gridf);
- pt->y = gridf * floorf(0.5f + pt->y / gridf);
- pt->z = gridf * floorf(0.5f + pt->z / gridf);
- }
- else {
- /* apply parent transformations */
- float fpt[3];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* apply parent transformations */
+ float fpt[3];
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
- fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf);
- fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf);
- fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf);
+ fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf);
+ fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf);
+ fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf);
- /* return data */
- copy_v3_v3(&pt->x, fpt);
- gp_apply_parent_point(gpl, pt);
- }
+ /* return data */
+ copy_v3_v3(&pt->x, fpt);
+ gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
}
}
}
}
}
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&obact->id, DEG_TAG_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -1463,6 +2097,8 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C); \
+ Object *obact = CTX_data_active_object(C); \
const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
const float *cursor_global = ED_view3d_cursor3d_get(scene, v3d)->location;
@@ -1473,10 +2109,8 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
bGPDframe *gpf = gpl->actframe;
float diff_mat[4][4];
- /* calculate difference matrix if parent object */
- if (gpl->parent != NULL) {
- ED_gpencil_parent_location(gpl, diff_mat);
- }
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
bGPDspoint *pt;
@@ -1486,7 +2120,7 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false)
continue;
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
if ((gps->flag & GP_STROKE_SELECT) == 0)
@@ -1509,9 +2143,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);
- if (gpl->parent != NULL) {
- gp_apply_parent_point(gpl, pt);
- }
+ gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
}
}
}
@@ -1520,6 +2152,8 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
}
}
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&obact->id, DEG_TAG_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -1551,6 +2185,8 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C); \
+ Object *obact = CTX_data_active_object(C); \
float *cursor = ED_view3d_cursor3d_get(scene, v3d)->location;
float centroid[3] = {0.0f};
@@ -1566,10 +2202,8 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
bGPDframe *gpf = gpl->actframe;
float diff_mat[4][4];
- /* calculate difference matrix if parent object */
- if (gpl->parent != NULL) {
- ED_gpencil_parent_location(gpl, diff_mat);
- }
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
bGPDspoint *pt;
@@ -1579,7 +2213,7 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false)
continue;
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
if ((gps->flag & GP_STROKE_SELECT) == 0)
@@ -1587,18 +2221,13 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
- if (gpl->parent == NULL) {
- add_v3_v3(centroid, &pt->x);
- minmax_v3v3_v3(min, max, &pt->x);
- }
- else {
- /* apply parent transformations */
- float fpt[3];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* apply parent transformations */
+ float fpt[3];
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
add_v3_v3(centroid, fpt);
- minmax_v3v3_v3(min, max, fpt);
- }
+ minmax_v3v3_v3(min, max, fpt);
+
count++;
}
}
@@ -1616,7 +2245,9 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
}
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+
return OPERATOR_FINISHED;
}
@@ -1650,13 +2281,20 @@ static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op))
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* Apply thickness */
- gps->thickness = gps->thickness + gpl->thickness;
+ if ((gps->thickness == 0) && (gpl->line_change == 0)) {
+ gps->thickness = gpl->thickness;
+ }
+ else {
+ gps->thickness = gps->thickness + gpl->line_change;
+ }
}
}
/* clear value */
gpl->thickness = 0.0f;
+ gpl->line_change = 0;
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1685,6 +2323,8 @@ enum {
static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
+
const int type = RNA_enum_get(op->ptr, "type");
/* sanity checks */
@@ -1698,13 +2338,13 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
continue;
for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
- bGPDpalettecolor *palcolor = gps->palcolor;
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
/* skip strokes that are not selected or invalid for current view */
if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false)
continue;
/* skip hidden or locked colors */
- if (!palcolor || (palcolor->flag & PC_COLOR_HIDE) || (palcolor->flag & PC_COLOR_LOCKED))
+ if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) || (gp_style->flag & GP_STYLE_COLOR_LOCKED))
continue;
switch (type) {
@@ -1729,6 +2369,7 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1809,15 +2450,24 @@ static void gpencil_flip_stroke(bGPDstroke *gps)
}
/* Helper: copy point between strokes */
-static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float delta[3],
+static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, int idx, float delta[3],
float pressure, float strength, float deltatime)
{
bGPDspoint *newpoint;
+ MDeformVert *dvert, *newdvert;
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++;
-
newpoint = &gps->points[gps->totpoints - 1];
+
+ if (gps->dvert != NULL) {
+ dvert = &gps->dvert[idx];
+ newdvert = &gps->dvert[gps->totpoints - 1];
+ }
+
newpoint->x = point->x * delta[0];
newpoint->y = point->y * delta[1];
newpoint->z = point->z * delta[2];
@@ -1825,6 +2475,9 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float
newpoint->pressure = pressure;
newpoint->strength = strength;
newpoint->time = point->time + deltatime;
+
+ newdvert->totweight = dvert->totweight;
+ newdvert->dw = MEM_dupallocN(dvert->dw);
}
/* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */
@@ -1870,18 +2523,18 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, co
/* 1st: add one tail point to start invisible area */
point = gps_a->points[gps_a->totpoints - 1];
deltatime = point.time;
- gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, 0.0f);
+ gpencil_stroke_copy_point(gps_a, &point, gps_a->totpoints - 1, delta, 0.0f, 0.0f, 0.0f);
/* 2nd: add one head point to finish invisible area */
point = gps_b->points[0];
- gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, deltatime);
+ gpencil_stroke_copy_point(gps_a, &point, 0, delta, 0.0f, 0.0f, deltatime);
}
/* 3rd: add all points */
for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
/* check if still room in buffer */
if (gps_a->totpoints <= GP_STROKE_BUFFER_MAX - 2) {
- gpencil_stroke_copy_point(gps_a, pt, delta, pt->pressure, pt->strength, deltatime);
+ gpencil_stroke_copy_point(gps_a, pt, i, delta, pt->pressure, pt->strength, deltatime);
}
}
}
@@ -1891,8 +2544,7 @@ 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;
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+ Object *ob = CTX_data_active_object(C);
bGPDframe *gpf_a = NULL;
bGPDstroke *stroke_a = NULL;
@@ -1928,7 +2580,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
continue;
}
@@ -1948,15 +2600,17 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op)
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_CACHES;
/* if new, set current color */
if (type == GP_STROKE_JOINCOPY) {
- new_stroke->palcolor = palcolor;
- BLI_strncpy(new_stroke->colorname, palcolor->info, sizeof(new_stroke->colorname));
- new_stroke->flag |= GP_STROKE_RECALC_COLOR;
+ new_stroke->mat_nr = stroke_a->mat_nr;
}
}
@@ -1995,6 +2649,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op)
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -2030,6 +2685,7 @@ void GPENCIL_OT_stroke_join(wmOperatorType *ot)
static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
/* sanity checks */
if (ELEM(NULL, gpd))
@@ -2049,7 +2705,7 @@ static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
continue;
}
@@ -2061,6 +2717,7 @@ static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_END;
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -2084,33 +2741,42 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
/* ***************** Reproject Strokes ********************** */
typedef enum eGP_ReprojectModes {
+ /* Axis (equal to lock axis) */
+ GP_REPROJECT_AXIS = 0,
/* On same plane, parallel to viewplane */
- GP_REPROJECT_PLANAR = 0,
+ GP_REPROJECT_PLANAR,
/* Reprojected on to the scene geometry */
GP_REPROJECT_SURFACE,
} eGP_ReprojectModes;
-static bool gp_strokes_reproject_poll(bContext *C)
-{
- /* 2 Requirements:
- * - 1) Editable GP data
- * - 2) 3D View only (2D editors don't have projection issues)
- */
- return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C));
-}
-
static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = CTX_data_active_object(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+ View3D *v3d = sa->spacedata.first;
+
GP_SpaceConversion gsc = {NULL};
- eGP_ReprojectModes mode = RNA_boolean_get(op->ptr, "type");
+ eGP_ReprojectModes mode = RNA_enum_get(op->ptr, "type");
+
+ int lock_axis = ts->gp_sculpt.lock_axis;
+ float origin[3];
+
+ if ((mode == GP_REPROJECT_AXIS) && (lock_axis == GP_LOCKAXIS_NONE)) {
+ BKE_report(op->reports, RPT_ERROR, "To reproject by axis, a lock axis must be set before");
+ return OPERATOR_CANCELLED;
+ }
/* init space conversion stuff */
gp_point_conversion_init(C, &gsc);
/* init autodist for geometry projection */
if (mode == GP_REPROJECT_SURFACE) {
- struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
view3d_region_operator_needs_opengl(CTX_wm_window(C), gsc.ar);
ED_view3d_autodist_init(depsgraph, gsc.ar, CTX_wm_view3d(C), 0);
}
@@ -2127,9 +2793,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
/* Compute inverse matrix for unapplying parenting once instead of doing per-point */
/* TODO: add this bit to the iteration macro? */
- if (gpl->parent) {
- invert_m4_m4(inverse_diff_mat, diff_mat);
- }
+ invert_m4_m4(inverse_diff_mat, diff_mat);
/* Adjust each point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
@@ -2140,19 +2804,28 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
* coordinates, resulting in lost precision, which in turn causes stairstepping
* artifacts in the final points.
*/
- if (gpl->parent == NULL) {
- gp_point_to_xy_fl(&gsc, gps, pt, &xy[0], &xy[1]);
- }
- else {
- bGPDspoint pt2;
- gp_point_to_parent_space(pt, diff_mat, &pt2);
- gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
+
+ /* Project stroke in the axis locked */
+ if (mode == GP_REPROJECT_AXIS) {
+ if (lock_axis > GP_LOCKAXIS_NONE) {
+ ED_gp_get_drawing_reference(v3d, scene, ob, gpl,
+ ts->gpencil_v3d_align, origin);
+ ED_gp_project_point_to_plane(ob, rv3d, origin,
+ lock_axis - 1, &pt2);
+
+ copy_v3_v3(&pt->x, &pt2.x);
+
+ /* apply parent again */
+ gp_apply_parent_point(depsgraph, ob, gpd, gpl, pt);
+ }
}
-
/* Project screenspace back to 3D space (from current perspective)
* so that all points have been treated the same way
*/
- if (mode == GP_REPROJECT_PLANAR) {
+ else if (mode == GP_REPROJECT_PLANAR) {
/* Planar - All on same plane parallel to the viewplane */
gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
}
@@ -2175,7 +2848,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
}
/* Unapply parent corrections */
- if (gpl->parent) {
+ if (mode != GP_REPROJECT_AXIS) {
mul_m4_v3(inverse_diff_mat, &pt->x);
}
}
@@ -2183,6 +2856,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
}
GP_EDITABLE_STROKES_END;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -2190,6 +2864,9 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_reproject(wmOperatorType *ot)
{
static const EnumPropertyItem reproject_type[] = {
+ { GP_REPROJECT_AXIS, "AXIS", 0, "Axis",
+ "Reproject the strokes using the current lock axis configuration. This is the same projection using while"
+ "drawing new strokes" },
{GP_REPROJECT_PLANAR, "PLANAR", 0, "Planar",
"Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint "
"using 'Cursor' Stroke Placement"},
@@ -2208,7 +2885,7 @@ void GPENCIL_OT_reproject(wmOperatorType *ot)
/* callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = gp_strokes_reproject_exec;
- ot->poll = gp_strokes_reproject_poll;
+ ot->poll = gp_strokes_edit3d_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2229,7 +2906,7 @@ static int gp_count_subdivision_cuts(bGPDstroke *gps)
if (pt->flag & GP_SPOINT_SELECT) {
if (i + 1 < gps->totpoints) {
if (gps->points[i + 1].flag & GP_SPOINT_SELECT) {
- ++totnewpoints;
+ totnewpoints++;
}
}
}
@@ -2237,6 +2914,7 @@ static int gp_count_subdivision_cuts(bGPDstroke *gps)
return totnewpoints;
}
+
static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
@@ -2267,6 +2945,9 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
/* resize the points arrys */
gps->totpoints += totnewpoints;
gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ }
gps->flag |= GP_STROKE_RECALC_CACHES;
/* loop and interpolate */
@@ -2275,19 +2956,27 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
bGPDspoint *pt = &temp_points[i];
bGPDspoint *pt_final = &gps->points[i2];
+ MDeformVert *dvert_final = &gps->dvert[i2];
+
/* copy current point */
copy_v3_v3(&pt_final->x, &pt->x);
pt_final->pressure = pt->pressure;
pt_final->strength = pt->strength;
pt_final->time = pt->time;
pt_final->flag = pt->flag;
- ++i2;
+
+ dvert_final->totweight = 0;
+ dvert_final->dw = NULL;
+ i2++;
/* if next point is selected add a half way point */
if (pt->flag & GP_SPOINT_SELECT) {
if (i + 1 < oldtotpoints) {
if (temp_points[i + 1].flag & GP_SPOINT_SELECT) {
pt_final = &gps->points[i2];
+ if (gps->dvert != NULL) {
+ dvert_final = &gps->dvert[i2];
+ }
/* Interpolate all values */
bGPDspoint *next = &temp_points[i + 1];
interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
@@ -2296,7 +2985,11 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt_final->time = interpf(pt->time, next->time, 0.5f);
pt_final->flag |= GP_SPOINT_SELECT;
- ++i2;
+
+ dvert_final->totweight = 0;
+ dvert_final->dw = NULL;
+
+ i2++;
}
}
}
@@ -2309,6 +3002,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
GP_EDITABLE_STROKES_END;
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -2328,7 +3022,7 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot)
ot->poll = gp_active_layer_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, 5);
@@ -2336,3 +3030,414 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+
+/* ** simplify stroke *** */
+static int gp_stroke_simplify_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ float factor = RNA_float_get(op->ptr, "factor");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* Go through each editable + selected stroke */
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* simplify stroke using Ramer-Douglas-Peucker algorithm */
+ BKE_gpencil_simplify_stroke(gps, factor);
+ }
+ }
+ GP_EDITABLE_STROKES_END;
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_simplify(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Simplify Stroke";
+ ot->idname = "GPENCIL_OT_stroke_simplify";
+ ot->description = "Simplify selected stroked reducing number of points";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_simplify_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, 100.0f, "Factor", "", 0.0f, 100.0f);
+ /* avoid re-using last var */
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/* ** simplify stroke using fixed algorith *** */
+static int gp_stroke_simplify_fixed_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ int steps = RNA_int_get(op->ptr, "step");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* Go through each editable + selected stroke */
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ for (int i = 0; i < steps; i++) {
+ BKE_gpencil_simplify_fixed(gps);
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END;
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_simplify_fixed(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Simplify Fixed Stroke";
+ ot->idname = "GPENCIL_OT_stroke_simplify_fixed";
+ ot->description = "Simplify selected stroked reducing number of points using fixed algorithm";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_simplify_fixed_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_int(ot->srna, "step", 1, 1, 100, "Steps", "Number of simplify steps", 1, 10);
+
+ /* avoid re-using last var */
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+}
+
+/* ***************** Separate Strokes ********************** */
+typedef enum eGP_SeparateModes {
+ /* Points */
+ GP_SEPARATE_POINT = 0,
+ /* Selected Strokes */
+ GP_SEPARATE_STROKE,
+ /* Current Layer */
+ GP_SEPARATE_LAYER,
+} eGP_SeparateModes;
+
+static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
+{
+ Base *base_new;
+ 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);
+ bGPdata *gpd_src = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
+
+ Object *ob_dst = NULL;
+ bGPdata *gpd_dst = NULL;
+ bGPDlayer *gpl_dst = NULL;
+ bGPDframe *gpf_dst = NULL;
+ bGPDspoint *pt;
+ Material *ma = NULL;
+ int i, idx;
+
+ eGP_SeparateModes mode = RNA_enum_get(op->ptr, "mode");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd_src)) {
+ return OPERATOR_CANCELLED;
+ }
+ bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_src);
+
+ /* create a new object */
+ base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, 0);
+ ob_dst = base_new->object;
+
+ /* create new grease pencil datablock */
+ // XXX: check usercounts
+ gpd_dst = BKE_gpencil_data_addnew(bmain, "GPencil");
+ ob_dst->data = (bGPdata *)gpd_dst;
+
+ int totslots = ob_dst->totcol;
+ int totadd = 0;
+
+ /* loop old datablock and separate parts */
+ if ((mode == GP_SEPARATE_POINT) || (mode == GP_SEPARATE_STROKE)) {
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ gpl_dst = NULL;
+ 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))) {
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL) {
+ continue;
+ }
+
+ gpf_dst = NULL;
+
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+ /* separate selected strokes */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* add layer if not created before */
+ if (gpl_dst == NULL) {
+ gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl->info, false);
+ }
+
+ /* add frame if not created before */
+ if (gpf_dst == NULL) {
+ gpf_dst = BKE_gpencil_layer_getframe(gpl_dst, gpf->framenum, GP_GETFRAME_ADD_NEW);
+ }
+
+ /* add duplicate materials */
+ ma = give_current_material(ob, gps->mat_nr + 1);
+ idx = BKE_object_material_slot_find_index(ob_dst, ma);
+ if (idx == 0) {
+
+ totadd++;
+ ob_dst->actcol = totadd;
+ ob_dst->totcol = totadd;
+
+ if (totadd > totslots) {
+ BKE_object_material_slot_add(bmain, ob_dst);
+ }
+
+ assign_material(bmain, ob_dst, ma, ob_dst->totcol, BKE_MAT_ASSIGN_EXISTING);
+ idx = totadd;
+ }
+
+ /* selected points mode */
+ if (mode == GP_SEPARATE_POINT) {
+ /* make copy of source stroke */
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps);
+
+ /* reasign material */
+ gps_dst->mat_nr = idx - 1;
+
+ /* link to destination frame */
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
+
+ /* Invert selection status of all points in destination stroke */
+ for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
+ pt->flag ^= GP_SPOINT_SELECT;
+ }
+
+ /* delete selected points from destination stroke */
+ gp_stroke_delete_tagged_points(gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false);
+
+ /* delete selected points from origin stroke */
+ gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false);
+ }
+ /* selected strokes mode */
+ else if (mode == GP_SEPARATE_STROKE) {
+ /* deselect old stroke */
+ gps->flag &= ~GP_STROKE_SELECT;
+ /* unlink from source frame */
+ BLI_remlink(&gpf->strokes, gps);
+ gps->prev = gps->next = NULL;
+ /* relink to destination frame */
+ BLI_addtail(&gpf_dst->strokes, gps);
+ /* reasign material */
+ gps->mat_nr = idx - 1;
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+ }
+ else if (mode == GP_SEPARATE_LAYER) {
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ if (gpl) {
+ /* try to set a new active layer in source datablock */
+ if (gpl->prev) {
+ BKE_gpencil_layer_setactive(gpd_src, gpl->prev);
+ }
+ else if (gpl->next) {
+ BKE_gpencil_layer_setactive(gpd_src, gpl->next);
+ }
+ /* unlink from source datablock */
+ BLI_remlink(&gpd_src->layers, gpl);
+ gpl->prev = gpl->next = NULL;
+ /* relink to destination datablock */
+ BLI_addtail(&gpd_dst->layers, gpl);
+ }
+ }
+ DEG_id_tag_update(&gpd_src->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&gpd_dst->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_separate(wmOperatorType *ot)
+{
+ static const EnumPropertyItem separate_type[] = {
+ {GP_SEPARATE_POINT, "POINT", 0, "Selected Points", "Separate the selected points" },
+ {GP_SEPARATE_STROKE, "STROKE", 0, "Selected Strokes", "Separate the selected strokes"},
+ {GP_SEPARATE_LAYER, "LAYER", 0, "Active Layer", "Separate the strokes of the current layer" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+ /* identifiers */
+ ot->name = "Separate Strokes";
+ ot->idname = "GPENCIL_OT_stroke_separate";
+ ot->description = "Separate the selected strokes or layer in a new grease pencil object";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gp_stroke_separate_exec;
+ ot->poll = gp_strokes_edit3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "mode", separate_type, GP_SEPARATE_POINT, "Mode", "");
+}
+
+/* ***************** Split Strokes ********************** */
+static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDspoint *pt;
+ int i;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+ bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
+ /* loop strokes and split parts */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ 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))) {
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL) {
+ continue;
+ }
+
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+ /* split selected strokes */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* make copy of source stroke */
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps);
+
+ /* link to same frame */
+ BLI_addtail(&gpf->strokes, gps_dst);
+
+ /* invert selection status of all points in destination stroke */
+ for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
+ pt->flag ^= GP_SPOINT_SELECT;
+ }
+
+ /* delete selected points from destination stroke */
+ gp_stroke_delete_tagged_points(gpf, gps_dst, NULL, GP_SPOINT_SELECT, true);
+
+ /* delete selected points from origin stroke */
+ gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false);
+ }
+ }
+ /* select again tagged points */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *ptn = gps->points;
+ for (int i2 = 0; i2 < gps->totpoints; i2++, ptn++) {
+ if (ptn->flag & GP_SPOINT_TAG) {
+ ptn->flag |= GP_SPOINT_SELECT;
+ ptn->flag &= ~GP_SPOINT_TAG;
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_split(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Split Strokes";
+ ot->idname = "GPENCIL_OT_stroke_split";
+ ot->description = "Split selected points as new stroke on same frame";
+
+ /* callbacks */
+ ot->exec = gp_stroke_split_exec;
+ ot->poll = gp_strokes_edit3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
new file mode 100644
index 00000000000..b768ac2c44f
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -0,0 +1,1246 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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, Joshua Leung
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/gpencil/gpencil_fill.c
+ * \ingroup edgpencil
+ */
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_stack.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_image_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_main.h"
+#include "BKE_brush.h"
+#include "BKE_image.h"
+#include "BKE_gpencil.h"
+#include "BKE_material.h"
+#include "BKE_context.h"
+#include "BKE_screen.h"
+#include "BKE_paint.h"
+
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_view3d.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "GPU_immediate.h"
+#include "GPU_draw.h"
+#include "GPU_matrix.h"
+#include "GPU_framebuffer.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "gpencil_intern.h"
+
+#define LEAK_HORZ 0
+#define LEAK_VERT 1
+
+
+/* Temporary fill operation data (op->customdata) */
+typedef struct tGPDfill {
+ struct Main *bmain;
+ struct Depsgraph *depsgraph;
+ struct wmWindow *win; /* window where painting originated */
+ struct Scene *scene; /* current scene from context */
+ struct Object *ob; /* current active gp object */
+ struct ScrArea *sa; /* area where painting originated */
+ struct RegionView3D *rv3d; /* region where painting originated */
+ struct View3D *v3d; /* view3 where painting originated */
+ struct ARegion *ar; /* region where painting originated */
+ struct bGPdata *gpd; /* current GP datablock */
+ struct Material *mat; /* current material */
+ struct bGPDlayer *gpl; /* layer */
+ struct bGPDframe *gpf; /* frame */
+
+ short flag; /* flags */
+ short oldkey; /* avoid too fast events */
+ bool on_back; /* send to back stroke */
+
+ int center[2]; /* mouse fill center position */
+ int sizex; /* windows width */
+ int sizey; /* window height */
+ int lock_axis; /* lock to viewport axis */
+
+ short fill_leak; /* number of pixel to consider the leak is too small (x 2) */
+ float fill_threshold; /* factor for transparency */
+ int fill_simplylvl; /* number of simplify steps */
+ int fill_draw_mode; /* boundary limits drawing mode */
+
+ short sbuffer_size; /* number of elements currently in cache */
+ void *sbuffer; /* temporary points */
+ float *depth_arr; /* depth array for reproject */
+
+ Image *ima; /* temp image */
+ BLI_Stack *stack; /* temp points data */
+ void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */
+} tGPDfill;
+
+
+ /* draw a given stroke using same thickness and color for all points */
+static void gp_draw_basic_stroke(tGPDfill *tgpf, bGPDstroke *gps, const float diff_mat[4][4],
+ bool cyclic, float ink[4], int flag, float thershold)
+{
+ bGPDspoint *points = gps->points;
+
+ Material *ma = tgpf->mat;
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+
+ int totpoints = gps->totpoints;
+ float fpt[3];
+ float col[4];
+
+ copy_v4_v4(col, ink);
+
+ /* if cyclic needs more vertex */
+ int cyclic_add = (cyclic) ? 1 : 0;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
+ /* draw stroke curve */
+ glLineWidth(1.0f);
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
+ const bGPDspoint *pt = points;
+
+ for (int i = 0; i < totpoints; i++, pt++) {
+
+ if (flag & GP_BRUSH_FILL_HIDE) {
+ float alpha = gp_style->stroke_rgba[3] * pt->strength;
+ CLAMP(alpha, 0.0f, 1.0f);
+ col[3] = alpha <= thershold ? 0.0f : 1.0f;
+ }
+ else {
+ col[3] = 1.0f;
+ }
+ /* set point */
+ immAttrib4fv(color, col);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ immVertex3fv(pos, fpt);
+ }
+
+ if (cyclic && totpoints > 2) {
+ /* draw line to first point to complete the cycle */
+ immAttrib4fv(color, col);
+ mul_v3_m4v3(fpt, diff_mat, &points->x);
+ immVertex3fv(pos, fpt);
+ }
+
+ immEnd();
+ immUnbindProgram();
+}
+
+/* loop all layers */
+static void gp_draw_datablock(tGPDfill *tgpf, float ink[4])
+{
+ /* duplicated: etempFlags */
+ enum {
+ GP_DRAWFILLS_NOSTATUS = (1 << 0), /* don't draw status info */
+ GP_DRAWFILLS_ONLY3D = (1 << 1), /* only draw 3d-strokes */
+ };
+
+ Object *ob = tgpf->ob;
+ bGPdata *gpd = tgpf->gpd;
+ int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
+
+ tGPDdraw tgpw;
+ tgpw.rv3d = tgpf->rv3d;
+ tgpw.depsgraph = tgpf->depsgraph;
+ tgpw.ob = ob;
+ tgpw.gpd = gpd;
+ tgpw.offsx = 0;
+ tgpw.offsy = 0;
+ tgpw.winx = tgpf->ar->winx;
+ tgpw.winy = tgpf->ar->winy;
+ tgpw.dflag = 0;
+ tgpw.disable_fill = 1;
+ tgpw.dflag |= (GP_DRAWFILLS_ONLY3D | GP_DRAWFILLS_NOSTATUS);
+
+ glEnable(GL_BLEND);
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* calculate parent position */
+ ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, tgpw.diff_mat);
+
+ /* do not draw layer if hidden */
+ if (gpl->flag & GP_LAYER_HIDE)
+ continue;
+
+ /* get frame to draw */
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0);
+ if (gpf == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* check if stroke can be drawn */
+ if ((gps->points == NULL) || (gps->totpoints < 2)) {
+ continue;
+ }
+ /* check if the color is visible */
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE))
+ {
+ continue;
+ }
+
+ tgpw.gps = gps;
+ tgpw.gpl = gpl;
+ tgpw.gpf = gpf;
+ tgpw.t_gpf = gpf;
+
+ /* reduce thickness to avoid gaps */
+ tgpw.lthick = gpl->line_change - 4;
+ tgpw.opacity = 1.0;
+ copy_v4_v4(tgpw.tintcolor, ink);
+ tgpw.onion = true;
+ tgpw.custonion = true;
+
+ /* normal strokes */
+ if ((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) ||
+ (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH))
+ {
+ ED_gp_draw_fill(&tgpw);
+
+ }
+
+ /* 3D Lines with basic shapes and invisible lines */
+ if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ||
+ (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH))
+ {
+ gp_draw_basic_stroke(tgpf, gps, tgpw.diff_mat, gps->flag & GP_STROKE_CYCLIC, ink,
+ tgpf->flag, tgpf->fill_threshold);
+ }
+ }
+ }
+
+ glDisable(GL_BLEND);
+}
+
+ /* draw strokes in offscreen buffer */
+static void gp_render_offscreen(tGPDfill *tgpf)
+{
+ bool is_ortho = false;
+ float winmat[4][4];
+
+ if (!tgpf->gpd) {
+ return;
+ }
+
+ char err_out[256] = "unknown";
+ GPUOffScreen *offscreen = GPU_offscreen_create(tgpf->sizex, tgpf->sizey, 0, true, false, err_out);
+ GPU_offscreen_bind(offscreen, true);
+ uint flag = IB_rect | IB_rectfloat;
+ ImBuf *ibuf = IMB_allocImBuf(tgpf->sizex, tgpf->sizey, 32, flag);
+
+ rctf viewplane;
+ float clipsta, clipend;
+
+ is_ortho = ED_view3d_viewplane_get(tgpf->depsgraph, tgpf->v3d, tgpf->rv3d, tgpf->sizex, tgpf->sizey, &viewplane, &clipsta, &clipend, NULL);
+ if (is_ortho) {
+ orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
+ }
+ else {
+ perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
+ }
+
+ /* set temporary new size */
+ int bwinx = tgpf->ar->winx;
+ int bwiny = tgpf->ar->winy;
+ rcti brect = tgpf->ar->winrct;
+
+ tgpf->ar->winx = (short) tgpf->sizex;
+ tgpf->ar->winy = (short) tgpf->sizey;
+ tgpf->ar->winrct.xmin = 0;
+ tgpf->ar->winrct.ymin = 0;
+ tgpf->ar->winrct.xmax = tgpf->sizex;
+ tgpf->ar->winrct.ymax = tgpf->sizey;
+
+ GPU_matrix_push_projection();
+ GPU_matrix_identity_set();
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ ED_view3d_update_viewmat(tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar,
+ NULL, winmat, NULL);
+ /* set for opengl */
+ GPU_matrix_projection_set(tgpf->rv3d->winmat);
+ GPU_matrix_set(tgpf->rv3d->viewmat);
+
+ /* draw strokes */
+ float ink[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
+ gp_draw_datablock(tgpf, ink);
+
+ /* restore size */
+ tgpf->ar->winx = (short)bwinx;
+ tgpf->ar->winy = (short)bwiny;
+ tgpf->ar->winrct = brect;
+
+ GPU_matrix_pop_projection();
+ GPU_matrix_pop();
+
+ /* create a image to see result of template */
+ if (ibuf->rect_float) {
+ GPU_offscreen_read_pixels(offscreen, GL_FLOAT, ibuf->rect_float);
+ }
+ else if (ibuf->rect) {
+ GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, ibuf->rect);
+ }
+ if (ibuf->rect_float && ibuf->rect) {
+ IMB_rect_from_float(ibuf);
+ }
+
+ tgpf->ima = BKE_image_add_from_imbuf(tgpf->bmain, ibuf, "GP_fill");
+ tgpf->ima->id.tag |= LIB_TAG_DOIT;
+
+ BKE_image_release_ibuf(tgpf->ima, ibuf, NULL);
+
+ /* switch back to window-system-provided framebuffer */
+ GPU_offscreen_unbind(offscreen, true);
+ GPU_offscreen_free(offscreen);
+}
+
+/* return pixel data (rgba) at index */
+static void get_pixel(ImBuf *ibuf, int idx, float r_col[4])
+{
+ if (ibuf->rect_float) {
+ float *frgba = &ibuf->rect_float[idx * 4];
+ copy_v4_v4(r_col, frgba);
+ }
+ else {
+ /* XXX: This case probably doesn't happen, as we only write to the float buffer,
+ * but we get compiler warnings about uninitialised vars otherwise
+ */
+ BLI_assert(!"gpencil_fill.c - get_pixel() non-float case is used!");
+ zero_v4(r_col);
+ }
+}
+
+/* set pixel data (rgba) at index */
+static void set_pixel(ImBuf *ibuf, int idx, const float col[4])
+{
+ if (ibuf->rect) {
+ uint *rrect = &ibuf->rect[idx];
+ uchar ccol[4];
+
+ rgba_float_to_uchar(ccol, col);
+ *rrect = *((uint *)ccol);
+ }
+
+ if (ibuf->rect_float) {
+ float *rrectf = &ibuf->rect_float[idx * 4];
+ copy_v4_v4(rrectf, col);
+ }
+}
+
+/* check if the size of the leak is narrow to determine if the stroke is closed
+ * this is used for strokes with small gaps between them to get a full fill
+ * and do not get a full screen fill.
+ *
+ * \param ibuf Image pixel data
+ * \param maxpixel Maximum index
+ * \param limit Limit of pixels to analize
+ * \param index Index of current pixel
+ * \param type 0-Horizontal 1-Vertical
+ */
+static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index, int type)
+{
+ float rgba[4];
+ int i;
+ int pt;
+ bool t_a = false;
+ bool t_b = false;
+
+ /* Horizontal leak (check vertical pixels)
+ * X
+ * X
+ * xB7
+ * X
+ * X
+ */
+ if (type == LEAK_HORZ) {
+ /* pixels on top */
+ for (i = 1; i <= limit; i++) {
+ pt = index + (ibuf->x * i);
+ if (pt <= maxpixel) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_a = true;
+ break;
+ }
+ }
+ else {
+ t_a = true; /* edge of image*/
+ break;
+ }
+ }
+ /* pixels on bottom */
+ for (i = 1; i <= limit; i++) {
+ pt = index - (ibuf->x * i);
+ if (pt >= 0) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_b = true;
+ break;
+ }
+ }
+ else {
+ t_b = true; /* edge of image*/
+ break;
+ }
+ }
+ }
+
+ /* Vertical leak (check horizontal pixels)
+ *
+ * XXXxB7XX
+ *
+ */
+ if (type == LEAK_VERT) {
+ /* get pixel range of the row */
+ int row = index / ibuf->x;
+ int lowpix = row * ibuf->x;
+ int higpix = lowpix + ibuf->x - 1;
+
+ /* pixels to right */
+ for (i = 0; i < limit; i++) {
+ pt = index - (limit - i);
+ if (pt >= lowpix) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_a = true;
+ break;
+ }
+ }
+ else {
+ t_a = true; /* edge of image*/
+ break;
+ }
+ }
+ /* pixels to left */
+ for (i = 0; i < limit; i++) {
+ pt = index + (limit - i);
+ if (pt <= higpix) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_b = true;
+ break;
+ }
+ }
+ else {
+ t_b = true; /* edge of image */
+ break;
+ }
+ }
+ }
+ return (bool)(t_a && t_b);
+}
+
+/* Boundary fill inside strokes
+ * Fills the space created by a set of strokes using the stroke color as the boundary
+ * of the shape to fill.
+ *
+ * \param tgpf Temporary fill data
+ */
+static void gpencil_boundaryfill_area(tGPDfill *tgpf)
+{
+ ImBuf *ibuf;
+ float rgba[4];
+ void *lock;
+ const float fill_col[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
+ ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
+ const int maxpixel = (ibuf->x * ibuf->y) - 1;
+
+ BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__);
+
+ /* calculate index of the seed point using the position of the mouse */
+ int index = (tgpf->sizex * tgpf->center[1]) + tgpf->center[0];
+ if ((index >= 0) && (index < maxpixel)) {
+ BLI_stack_push(stack, &index);
+ }
+
+ /* the fill use a stack to save the pixel list instead of the common recursive
+ * 4-contact point method.
+ * The problem with recursive calls is that for big fill areas, we can get max limit
+ * of recursive calls and STACK_OVERFLOW error.
+ *
+ * The 4-contact point analyze the pixels to the left, right, bottom and top
+ * -----------
+ * | X |
+ * | XoX |
+ * | X |
+ * -----------
+ */
+ while (!BLI_stack_is_empty(stack)) {
+ int v;
+ BLI_stack_pop(stack, &v);
+
+ get_pixel(ibuf, v, rgba);
+
+ if (true) { /* Was: 'rgba' */
+ /* check if no border(red) or already filled color(green) */
+ if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f))
+ {
+ /* fill current pixel */
+ set_pixel(ibuf, v, fill_col);
+
+ /* add contact pixels */
+ /* pixel left */
+ if (v - 1 >= 0) {
+ index = v - 1;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel right */
+ if (v + 1 < maxpixel) {
+ index = v + 1;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel top */
+ if (v + tgpf->sizex < maxpixel) {
+ index = v + tgpf->sizex;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel bottom */
+ if (v - tgpf->sizex >= 0) {
+ index = v - tgpf->sizex;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ }
+ }
+ }
+
+ /* release ibuf */
+ if (ibuf) {
+ BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
+ }
+
+ tgpf->ima->id.tag |= LIB_TAG_DOIT;
+ /* free temp stack data */
+ BLI_stack_free(stack);
+}
+
+/* clean external border of image to avoid infinite loops */
+static void gpencil_clean_borders(tGPDfill *tgpf)
+{
+ ImBuf *ibuf;
+ void *lock;
+ const float fill_col[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
+ int idx;
+
+ /* horizontal lines */
+ for (idx = 0; idx < ibuf->x; idx++) {
+ /* bottom line */
+ set_pixel(ibuf, idx, fill_col);
+ /* top line */
+ set_pixel(ibuf, idx + (ibuf->x * (ibuf->y - 1)), fill_col);
+ }
+ /* vertical lines */
+ for (idx = 0; idx < ibuf->y; idx++) {
+ /* left line */
+ set_pixel(ibuf, ibuf->x * idx, fill_col);
+ /* right line */
+ set_pixel(ibuf, ibuf->x * idx + (ibuf->x - 1), fill_col);
+ }
+
+ /* release ibuf */
+ if (ibuf) {
+ BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
+ }
+
+ tgpf->ima->id.tag |= LIB_TAG_DOIT;
+}
+
+/* Get the outline points of a shape using Moore Neighborhood algorithm
+ *
+ * This is a Blender customized version of the general algorithm described
+ * in https://en.wikipedia.org/wiki/Moore_neighborhood
+ */
+static void gpencil_get_outline_points(tGPDfill *tgpf)
+{
+ ImBuf *ibuf;
+ float rgba[4];
+ void *lock;
+ int v[2];
+ int boundary_co[2];
+ int start_co[2];
+ int backtracked_co[2];
+ int current_check_co[2];
+ int prev_check_co[2];
+ int backtracked_offset[1][2] = { { 0,0 } };
+ // bool boundary_found = false;
+ bool start_found = false;
+ const int NEIGHBOR_COUNT = 8;
+
+ int offset[8][2] = {
+ { -1, -1 },
+ { 0, -1 },
+ { 1, -1 },
+ { 1, 0 },
+ { 1, 1 },
+ { 0, 1 },
+ { -1, 1 },
+ { -1, 0 }
+ };
+
+ tgpf->stack = BLI_stack_new(sizeof(int[2]), __func__);
+
+ ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
+ int imagesize = ibuf->x * ibuf->y;
+
+ /* find the initial point to start outline analysis */
+ for (int idx = imagesize; idx >= 0; idx--) {
+ get_pixel(ibuf, idx, rgba);
+ if (rgba[1] == 1.0f) {
+ boundary_co[0] = idx % ibuf->x;
+ boundary_co[1] = idx / ibuf->x;
+ copy_v2_v2_int(start_co, boundary_co);
+ backtracked_co[0] = (idx - 1) % ibuf->x;
+ backtracked_co[1] = (idx - 1) / ibuf->x;
+ backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
+ backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
+ copy_v2_v2_int(prev_check_co, start_co);
+
+ BLI_stack_push(tgpf->stack, &boundary_co);
+ start_found = true;
+ break;
+ }
+ }
+
+ while (true && start_found)
+ {
+ int cur_back_offset = -1;
+ for (int i = 0; i < NEIGHBOR_COUNT; i++) {
+ if (backtracked_offset[0][0] == offset[i][0] &&
+ backtracked_offset[0][1] == offset[i][1])
+ {
+ /* Finding the bracktracked pixel offset index */
+ cur_back_offset = i;
+ break;
+ }
+ }
+
+ int loop = 0;
+ while (loop < (NEIGHBOR_COUNT - 1) && cur_back_offset != -1) {
+ int offset_idx = (cur_back_offset + 1) % NEIGHBOR_COUNT;
+ current_check_co[0] = boundary_co[0] + offset[offset_idx][0];
+ current_check_co[1] = boundary_co[1] + offset[offset_idx][1];
+
+ int image_idx = ibuf->x * current_check_co[1] + current_check_co[0];
+ get_pixel(ibuf, image_idx, rgba);
+
+ /* find next boundary pixel */
+ if (rgba[1] == 1.0f) {
+ copy_v2_v2_int(boundary_co, current_check_co);
+ copy_v2_v2_int(backtracked_co, prev_check_co);
+ backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
+ backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
+
+ BLI_stack_push(tgpf->stack, &boundary_co);
+
+ break;
+ }
+ copy_v2_v2_int(prev_check_co, current_check_co);
+ cur_back_offset++;
+ loop++;
+ }
+ /* current pixel is equal to starting pixel */
+ if (boundary_co[0] == start_co[0] &&
+ boundary_co[1] == start_co[1])
+ {
+ BLI_stack_pop(tgpf->stack, &v);
+ // boundary_found = true;
+ break;
+ }
+ }
+
+ /* release ibuf */
+ if (ibuf) {
+ BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
+ }
+}
+
+/* get z-depth array to reproject on surface */
+static void gpencil_get_depth_array(tGPDfill *tgpf)
+{
+ tGPspoint *ptc;
+ ToolSettings *ts = tgpf->scene->toolsettings;
+ int totpoints = tgpf->sbuffer_size;
+ int i = 0;
+
+ if (totpoints == 0) {
+ return;
+ }
+
+ /* for surface sketching, need to set the right OpenGL context stuff so that
+ * the conversions will project the values correctly...
+ */
+ if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) {
+ /* need to restore the original projection settings before packing up */
+ view3d_region_operator_needs_opengl(tgpf->win, tgpf->ar);
+ ED_view3d_autodist_init(tgpf->depsgraph, tgpf->ar, tgpf->v3d, 0);
+
+ /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
+ int depth_margin = 0;
+
+ /* get an array of depths, far depths are blended */
+ int mval[2], mval_prev[2] = { 0 };
+ int interp_depth = 0;
+ int found_depth = 0;
+
+ tgpf->depth_arr = MEM_mallocN(sizeof(float) * totpoints, "depth_points");
+
+ for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) {
+ copy_v2_v2_int(mval, &ptc->x);
+
+ if ((ED_view3d_autodist_depth(tgpf->ar, mval, depth_margin, tgpf->depth_arr + i) == 0) &&
+ (i && (ED_view3d_autodist_depth_seg(tgpf->ar, mval, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0)))
+ {
+ interp_depth = true;
+ }
+ else {
+ found_depth = true;
+ }
+
+ copy_v2_v2_int(mval_prev, mval);
+ }
+
+ if (found_depth == false) {
+ /* eeh... not much we can do.. :/, ignore depth in this case */
+ for (i = totpoints - 1; i >= 0; i--)
+ tgpf->depth_arr[i] = 0.9999f;
+ }
+ else {
+ if (interp_depth) {
+ interp_sparse_array(tgpf->depth_arr, totpoints, FLT_MAX);
+ }
+ }
+ }
+}
+
+/* create array of points using stack as source */
+static void gpencil_points_from_stack(tGPDfill *tgpf)
+{
+ tGPspoint *point2D;
+ int totpoints = BLI_stack_count(tgpf->stack);
+ if (totpoints == 0) {
+ return;
+ }
+
+ tgpf->sbuffer_size = (short)totpoints;
+ tgpf->sbuffer = MEM_callocN(sizeof(tGPspoint) * totpoints, __func__);
+
+ point2D = tgpf->sbuffer;
+ while (!BLI_stack_is_empty(tgpf->stack)) {
+ int v[2];
+ BLI_stack_pop(tgpf->stack, &v);
+ point2D->x = v[0];
+ point2D->y = v[1];
+
+ point2D->pressure = 1.0f;
+ point2D->strength = 1.0f;;
+ point2D->time = 0.0f;
+ point2D++;
+ }
+}
+
+/* create a grease pencil stroke using points in buffer */
+static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
+{
+ ToolSettings *ts = tgpf->scene->toolsettings;
+ int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
+
+ Brush *brush;
+ brush = BKE_brush_getactive_gpencil(ts);
+ if (brush == NULL) {
+ return;
+ }
+
+ bGPDspoint *pt;
+ MDeformVert *dvert;
+ tGPspoint *point2D;
+
+ if (tgpf->sbuffer_size == 0) {
+ return;
+ }
+
+ /* get frame or create a new one */
+ tgpf->gpf = BKE_gpencil_layer_getframe(tgpf->gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
+
+ /* create new stroke */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
+ gps->thickness = brush->size;
+ gps->inittime = 0.0f;
+
+ /* the polygon must be closed, so enabled cyclic */
+ gps->flag |= GP_STROKE_CYCLIC;
+ gps->flag |= GP_STROKE_3DSPACE;
+
+ gps->mat_nr = BKE_object_material_slot_find_index(tgpf->ob, tgpf->mat) - 1;
+
+ /* allocate memory for storage points */
+ gps->totpoints = tgpf->sbuffer_size;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * tgpf->sbuffer_size, "gp_stroke_points");
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * tgpf->sbuffer_size, "gp_stroke_weights");
+
+ /* initialize triangle memory to dummy data */
+ gps->tot_triangles = 0;
+ gps->triangles = NULL;
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* add stroke to frame */
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)){
+ BLI_addhead(&tgpf->gpf->strokes, gps);
+ }
+ else {
+ BLI_addtail(&tgpf->gpf->strokes, gps);
+ }
+
+ /* add points */
+ pt = gps->points;
+ dvert = gps->dvert;
+ point2D = (tGPspoint *)tgpf->sbuffer;
+ for (int i = 0; i < tgpf->sbuffer_size && point2D; i++, point2D++, pt++, dvert++) {
+ /* convert screen-coordinates to 3D coordinates */
+ gp_stroke_convertcoords_tpoint(tgpf->scene, tgpf->ar, tgpf->v3d, tgpf->ob,
+ tgpf->gpl, point2D,
+ tgpf->depth_arr ? tgpf->depth_arr + i : NULL,
+ &pt->x);
+
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;;
+ pt->time = 0.0f;
+
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ }
+
+ /* smooth stroke */
+ float reduce = 0.0f;
+ float smoothfac = 1.0f;
+ for (int r = 0; r < 1; r++) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ BKE_gpencil_smooth_stroke(gps, i, smoothfac - reduce);
+ }
+ reduce += 0.25f; // reduce the factor
+ }
+
+ /* if axis locked, reproject to plane locked */
+ if ((tgpf->lock_axis > GP_LOCKAXIS_NONE) && ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) {
+ float origin[3];
+ ED_gp_get_drawing_reference(tgpf->v3d, tgpf->scene, tgpf->ob, tgpf->gpl,
+ ts->gpencil_v3d_align, origin);
+ ED_gp_project_stroke_to_plane(tgpf->ob, tgpf->rv3d, gps, origin,
+ tgpf->lock_axis - 1);
+ }
+
+ /* if parented change position relative to parent object */
+ for (int a = 0; a < tgpf->sbuffer_size; a++) {
+ pt = &gps->points[a];
+ gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpd, tgpf->gpl, pt);
+ }
+
+ /* simplify stroke */
+ for (int b = 0; b < tgpf->fill_simplylvl; b++) {
+ BKE_gpencil_simplify_fixed(gps);
+ }
+}
+
+/* ----------------------- */
+/* Drawing */
+/* Helper: Draw status message while the user is running the operator */
+static void gpencil_fill_status_indicators(bContext *C, tGPDfill *UNUSED(tgpf))
+{
+ char status_str[UI_MAX_DRAW_STR];
+
+ BLI_snprintf(status_str, sizeof(status_str), IFACE_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back"));
+ ED_workspace_status_text(C, status_str);
+}
+
+/* draw boundary lines to see fill limits */
+static void gpencil_draw_boundary_lines(const bContext *UNUSED(C), tGPDfill *tgpf)
+{
+ if (!tgpf->gpd) {
+ return;
+ }
+ float ink[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
+ gp_draw_datablock(tgpf, ink);
+}
+
+/* Drawing callback for modal operator in 3d mode */
+static void gpencil_fill_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg)
+{
+ tGPDfill *tgpf = (tGPDfill *)arg;
+ /* draw only in the region that originated operator. This is required for multiwindow */
+ ARegion *ar = CTX_wm_region(C);
+ if (ar != tgpf->ar) {
+ return;
+ }
+
+ gpencil_draw_boundary_lines(C, tgpf);
+}
+
+/* check if context is suitable for filling */
+static bool gpencil_fill_poll(bContext *C)
+{
+ if (ED_operator_regionactive(C)) {
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa->spacetype == SPACE_VIEW3D) {
+ return 1;
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not valid for filling operator");
+ return 0;
+ }
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not set");
+ return 0;
+ }
+}
+
+/* Allocate memory and initialize values */
+static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op))
+{
+ tGPDfill *tgpf = MEM_callocN(sizeof(tGPDfill), "GPencil Fill Data");
+
+ /* define initial values */
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Main *bmain = CTX_data_main(C);
+
+ /* set current scene and window info */
+ tgpf->bmain = CTX_data_main(C);
+ tgpf->scene = CTX_data_scene(C);
+ tgpf->ob = CTX_data_active_object(C);
+ tgpf->sa = CTX_wm_area(C);
+ tgpf->ar = CTX_wm_region(C);
+ tgpf->rv3d = tgpf->ar->regiondata;
+ tgpf->v3d = tgpf->sa->spacedata.first;
+ tgpf->depsgraph = CTX_data_depsgraph(C);
+ tgpf->win = CTX_wm_window(C);
+
+ /* set GP datablock */
+ tgpf->gpd = gpd;
+ tgpf->gpl = BKE_gpencil_layer_getactive(gpd);
+
+ tgpf->lock_axis = ts->gp_sculpt.lock_axis;
+
+ tgpf->oldkey = -1;
+ tgpf->sbuffer_size = 0;
+ tgpf->sbuffer = NULL;
+ tgpf->depth_arr = NULL;
+
+ /* save filling parameters */
+ Brush *brush = BKE_brush_getactive_gpencil(ts);
+ tgpf->flag = brush->gpencil_settings->flag;
+ tgpf->fill_leak = brush->gpencil_settings->fill_leak;
+ tgpf->fill_threshold = brush->gpencil_settings->fill_threshold;
+ tgpf->fill_simplylvl = brush->gpencil_settings->fill_simplylvl;
+ tgpf->fill_draw_mode = brush->gpencil_settings->fill_draw_mode;
+
+ /* get color info */
+ Material *ma = BKE_gpencil_get_material_from_brush(brush);
+ /* if no brush defaults, get material and color info */
+ if ((ma == NULL) || (ma->gp_style == NULL)) {
+ ma = BKE_gpencil_material_ensure(bmain, tgpf->ob);
+ /* assign always the first material to the brush */
+ brush->gpencil_settings->material = give_current_material(tgpf->ob, 1);
+ }
+
+ tgpf->mat = ma;
+
+ /* init undo */
+ gpencil_undo_init(tgpf->gpd);
+
+ /* return context data for running operator */
+ return tgpf;
+}
+
+/* end operator */
+static void gpencil_fill_exit(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+
+ /* clear undo stack */
+ gpencil_undo_finish();
+
+ /* restore cursor to indicate end of fill */
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ tGPDfill *tgpf = op->customdata;
+
+ /* don't assume that operator data exists at all */
+ if (tgpf) {
+ /* clear status message area */
+ ED_workspace_status_text(C, NULL);
+
+ MEM_SAFE_FREE(tgpf->sbuffer);
+ MEM_SAFE_FREE(tgpf->depth_arr);
+
+ /* remove drawing handler */
+ if (tgpf->draw_handle_3d) {
+ ED_region_draw_cb_exit(tgpf->ar->type, tgpf->draw_handle_3d);
+ }
+
+ /* delete temp image */
+ if (tgpf->ima) {
+ for (Image *ima = bmain->image.first; ima; ima = ima->id.next) {
+ if (ima == tgpf->ima) {
+ BLI_remlink(&bmain->image, ima);
+ BKE_image_free(tgpf->ima);
+ MEM_SAFE_FREE(tgpf->ima);
+ break;
+ }
+ }
+ }
+
+ /* finally, free memory used by temp data */
+ MEM_freeN(tgpf);
+ }
+
+ /* clear pointer */
+ op->customdata = NULL;
+
+ /* drawing batch cache is dirty now */
+ if ((ob) && (ob->type == OB_GPENCIL) && (ob->data)) {
+ bGPdata *gpd2 = ob->data;
+ DEG_id_tag_update(&gpd2->id, OB_RECALC_OB | OB_RECALC_DATA);
+ gpd2->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+}
+
+static void gpencil_fill_cancel(bContext *C, wmOperator *op)
+{
+ /* this is just a wrapper around exit() */
+ gpencil_fill_exit(C, op);
+}
+
+/* Init: Allocate memory and set init values */
+static int gpencil_fill_init(bContext *C, wmOperator *op)
+{
+ tGPDfill *tgpf;
+
+ /* check context */
+ tgpf = op->customdata = gp_session_init_fill(C, op);
+ if (tgpf == NULL) {
+ /* something wasn't set correctly in context */
+ gpencil_fill_exit(C, op);
+ return 0;
+ }
+
+ /* everything is now setup ok */
+ return 1;
+}
+
+/* start of interactive part of operator */
+static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ tGPDfill *tgpf = NULL;
+
+ /* try to initialize context data needed */
+ if (!gpencil_fill_init(C, op)) {
+ gpencil_fill_exit(C, op);
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ tgpf = op->customdata;
+ }
+
+ /* Enable custom drawing handlers to show help lines */
+ if (tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) {
+ tgpf->draw_handle_3d = ED_region_draw_cb_activate(tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW);
+ }
+
+ WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR);
+
+ gpencil_fill_status_indicators(C, tgpf);
+
+ DEG_id_tag_update(&tgpf->gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* add a modal handler for this operator*/
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* events handling during interactive part of operator */
+static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGPDfill *tgpf = op->customdata;
+
+ int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through */
+
+ switch (event->type) {
+ case ESCKEY:
+ case RIGHTMOUSE:
+ estate = OPERATOR_CANCELLED;
+ break;
+ case LEFTMOUSE:
+ tgpf->on_back = RNA_boolean_get(op->ptr, "on_back");
+ /* first time the event is not enabled to show help lines */
+ if ((tgpf->oldkey != -1) || ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) == 0)) {
+ ARegion *ar = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->x, event->y);
+ if (ar) {
+ bool in_bounds = false;
+
+ /* Perform bounds check */
+ in_bounds = BLI_rcti_isect_pt(&ar->winrct, event->x, event->y);
+
+ if ((in_bounds) && (ar->regiontype == RGN_TYPE_WINDOW)) {
+ /* TODO GPXX: Verify the mouse click is right for any window size */
+ tgpf->center[0] = event->mval[0];
+ tgpf->center[1] = event->mval[1];
+
+ /* save size */
+ tgpf->sizex = ar->winx;
+ tgpf->sizey = ar->winy;
+
+ /* render screen to temp image */
+ gp_render_offscreen(tgpf);
+
+ /* apply boundary fill */
+ gpencil_boundaryfill_area(tgpf);
+
+ /* clean borders to avoid infinite loops */
+ gpencil_clean_borders(tgpf);
+
+ /* analyze outline */
+ gpencil_get_outline_points(tgpf);
+
+ /* create array of points from stack */
+ gpencil_points_from_stack(tgpf);
+
+ /* create z-depth array for reproject */
+ gpencil_get_depth_array(tgpf);
+
+ /* create stroke and reproject */
+ gpencil_stroke_from_buffer(tgpf);
+
+ /* free temp stack data */
+ if (tgpf->stack) {
+ BLI_stack_free(tgpf->stack);
+ }
+
+ /* push undo data */
+ gpencil_undo_push(tgpf->gpd);
+
+ estate = OPERATOR_FINISHED;
+ }
+ else {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ else {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ tgpf->oldkey = event->type;
+ break;
+ }
+ /* process last operations before exiting */
+ switch (estate) {
+ case OPERATOR_FINISHED:
+ gpencil_fill_exit(C, op);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ break;
+
+ case OPERATOR_CANCELLED:
+ gpencil_fill_exit(C, op);
+ break;
+
+ case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
+ break;
+ }
+
+ /* return status code */
+ return estate;
+}
+
+void GPENCIL_OT_fill(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Grease Pencil Fill";
+ ot->idname = "GPENCIL_OT_fill";
+ ot->description = "Fill with color the shape formed by strokes";
+
+ /* api callbacks */
+ ot->invoke = gpencil_fill_invoke;
+ ot->modal = gpencil_fill_modal;
+ ot->poll = gpencil_fill_poll;
+ ot->cancel = gpencil_fill_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ prop = RNA_def_boolean(ot->srna, "on_back", false, "Draw On Back", "Send new stroke to Back");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 90ff1e0bb25..0218530be4e 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -34,25 +34,145 @@
#include "DNA_vec_types.h"
+#include "ED_numinput.h"
+
/* internal exports only */
struct bGPdata;
struct bGPDstroke;
struct bGPDspoint;
+struct tGPspoint;
+struct Material;
struct GHash;
struct RNG;
+struct Brush;
+struct Scene;
struct ARegion;
+struct View3D;
struct View2D;
struct wmOperatorType;
+struct Depsgraph;
+
struct PointerRNA;
struct PropertyRNA;
struct EnumPropertyItem;
/* ***************************************************** */
+/* Modal Operator Geometry Preview
+ *
+ * Several modal operators (Fill, Interpolate, Primitive)
+ * need to run some drawing code to display previews, or
+ * to perform screen-space/image-based analysis routines.
+ * The following structs + function prototypes are used
+ * by these operators so that the operator code
+ * (in gpencil_<opname>.c) can communicate with the drawing
+ * code (in drawgpencil.c).
+ *
+ * NOTE: All this is within the gpencil module, so nothing needs
+ * to be exported to other modules.
+ */
+
+/* Internal Operator-State Data ------------------------ */
+
+/* Temporary draw data (no draw manager mode) */
+typedef struct tGPDdraw {
+ struct RegionView3D *rv3d; /* region to draw */
+ struct Depsgraph *depsgraph; /* depsgraph */
+ struct Object *ob; /* GP object */
+ struct bGPdata *gpd; /* current GP datablock */
+ struct bGPDlayer *gpl; /* layer */
+ struct bGPDframe *gpf; /* frame */
+ struct bGPDframe *t_gpf; /* temporal frame */
+ struct bGPDstroke *gps; /* stroke */
+ int disable_fill; /* disable fill */
+ int offsx; /* windows offset x */
+ int offsy; /* windows offset y */
+ int winx; /* windows width */
+ int winy; /* windows height */
+ int dflag; /* flags datablock */
+ short lthick; /* layer thickness */
+ float opacity; /* opacity */
+ float tintcolor[4]; /* tint color */
+ bool onion; /* onion flag */
+ bool custonion; /* use custom onion colors */
+ float diff_mat[4][4]; /* matrix */
+} tGPDdraw;
+
+
+/* Temporary interpolate operation data */
+typedef struct tGPDinterpolate_layer {
+ struct tGPDinterpolate_layer *next, *prev;
+
+ struct bGPDlayer *gpl; /* layer */
+ struct bGPDframe *prevFrame; /* frame before current frame (interpolate-from) */
+ struct bGPDframe *nextFrame; /* frame after current frame (interpolate-to) */
+ struct bGPDframe *interFrame; /* interpolated frame */
+ float factor; /* interpolate factor */
+
+} tGPDinterpolate_layer;
+
+typedef struct tGPDinterpolate {
+ struct Scene *scene; /* current scene from context */
+ struct ScrArea *sa; /* area where painting originated */
+ struct ARegion *ar; /* region where painting originated */
+ struct bGPdata *gpd; /* current GP datablock */
+ struct Material *mat; /* current material */
+
+ int cframe; /* current frame number */
+ ListBase ilayers; /* (tGPDinterpolate_layer) layers to be interpolated */
+ float shift; /* value for determining the displacement influence */
+ float init_factor; /* initial interpolation factor for active layer */
+ float low_limit; /* shift low limit (-100%) */
+ float high_limit; /* shift upper limit (200%) */
+ int flag; /* flag from toolsettings */
+
+ NumInput num; /* numeric input */
+ void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */
+ void *draw_handle_screen; /* handle for drawing strokes while operator is running screen stuff */
+} tGPDinterpolate;
+
+
+/* Temporary primitive operation data */
+typedef struct tGPDprimitive {
+ struct Depsgraph *depsgraph;
+ struct wmWindow *win; /* window where painting originated */
+ struct Scene *scene; /* current scene from context */
+ struct Object *ob; /* current active gp object */
+ struct ScrArea *sa; /* area where painting originated */
+ struct RegionView3D *rv3d; /* region where painting originated */
+ struct View3D *v3d; /* view3d where painting originated */
+ struct ARegion *ar; /* region where painting originated */
+ struct bGPdata *gpd; /* current GP datablock */
+ struct Material *mat; /* current material */
+ struct Brush *brush; /* current brush */
+
+ int cframe; /* current frame number */
+ struct bGPDlayer *gpl; /* layer */
+ struct bGPDframe *gpf; /* frame */
+ int type; /* type of primitive */
+ int tot_edges; /* number of polygon edges */
+ int top[2]; /* first box corner */
+ int bottom[2]; /* last box corner */
+ int flag; /* flag to determine operations in progress */
+
+ int lock_axis; /* lock to viewport axis */
+
+ NumInput num; /* numeric input */
+ void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */
+} tGPDprimitive;
+
+
+/* Modal Operator Drawing Callbacks ------------------------ */
+
+void ED_gp_draw_interpolation(const struct bContext *C, struct tGPDinterpolate *tgpi, const int type);
+void ED_gp_draw_primitives(const struct bContext *C, struct tGPDprimitive *tgpi, const int type);
+void ED_gp_draw_fill(struct tGPDdraw *tgpw);
+
+/* ***************************************************** */
/* Internal API */
/* Stroke Coordinates API ------------------------------ */
@@ -84,21 +204,29 @@ void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
float *r_x, float *r_y);
void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt);
-
-void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps);
-
-void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt);
+/**
+ * Change points position relative to parent object
+ */
+void gp_apply_parent(struct Depsgraph *depsgraph, struct Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps);
+/**
+ * Change point position relative to parent object
+ */
+void gp_apply_parent_point(struct Depsgraph *depsgraph, struct Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDspoint *pt);
bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, struct Scene *scene, const float screen_co[2], float r_out[3]);
+/* helper to convert 2d to 3d */
+void gp_stroke_convertcoords_tpoint(struct Scene *scene, struct ARegion *ar,
+ struct View3D *v3d, struct Object *ob,
+ bGPDlayer *gpl, const struct tGPspoint *point2D,
+ float *depth, float out[3]);
+
/* Poll Callbacks ------------------------------------ */
/* gpencil_utils.c */
bool gp_add_poll(struct bContext *C);
bool gp_active_layer_poll(struct bContext *C);
bool gp_active_brush_poll(struct bContext *C);
-bool gp_active_palette_poll(struct bContext *C);
-bool gp_active_palettecolor_poll(struct bContext *C);
bool gp_brush_crt_presets_poll(bContext *C);
/* Copy/Paste Buffer --------------------------------- */
@@ -107,18 +235,19 @@ bool gp_brush_crt_presets_poll(bContext *C);
extern ListBase gp_strokes_copypastebuf;
/* Build a map for converting between old colornames and destination-color-refs */
-struct GHash *gp_copybuf_validate_colormap(bGPdata *gpd);
+struct GHash *gp_copybuf_validate_colormap(struct bContext *C);
/* Stroke Editing ------------------------------------ */
-void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags);
-
+void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke,
+ int tag_flags, bool select);
+int gp_delete_selected_point_wrap(bContext *C);
bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure);
bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf);
bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf);
-void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints);
-void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush, struct RNG *rng);
+void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide);
+void gp_randomize_stroke(bGPDstroke *gps, Brush *brush, struct RNG *rng);
/* Layers Enums -------------------------------------- */
@@ -129,22 +258,18 @@ const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(
struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
bool *r_free);
-/* Enums of GP Brushes */
-const EnumPropertyItem *ED_gpencil_brushes_enum_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
- bool *r_free);
-
-/* Enums of GP palettes */
-const EnumPropertyItem *ED_gpencil_palettes_enum_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
- bool *r_free);
-
/* ***************************************************** */
/* Operator Defines */
+/* annotations ------ */
+
+void GPENCIL_OT_annotate(struct wmOperatorType *ot);
+
+
/* drawing ---------- */
void GPENCIL_OT_draw(struct wmOperatorType *ot);
+void GPENCIL_OT_fill(struct wmOperatorType *ot);
/* Paint Modes for operator */
typedef enum eGPencil_PaintModes {
@@ -160,7 +285,11 @@ typedef enum eGPencil_PaintModes {
/* stroke editing ----- */
void GPENCIL_OT_editmode_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_selection_opacity_toggle(struct wmOperatorType *ot);
+void GPENCIL_OT_multiedit_toggle(struct wmOperatorType *ot);
void GPENCIL_OT_select(struct wmOperatorType *ot);
void GPENCIL_OT_select_all(struct wmOperatorType *ot);
@@ -174,6 +303,7 @@ void GPENCIL_OT_select_more(struct wmOperatorType *ot);
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_duplicate(struct wmOperatorType *ot);
void GPENCIL_OT_delete(struct wmOperatorType *ot);
@@ -218,6 +348,8 @@ void GPENCIL_OT_blank_frame_add(struct wmOperatorType *ot);
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot);
+void GPENCIL_OT_frame_duplicate(struct wmOperatorType *ot);
+void GPENCIL_OT_frame_clean_fill(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
@@ -226,6 +358,13 @@ enum {
GP_STROKE_JOINCOPY = 1
};
+enum {
+ GP_STROKE_BOX = -1,
+ GP_STROKE_LINE = 1,
+ GP_STROKE_CIRCLE = 2
+};
+
+
void GPENCIL_OT_stroke_arrange(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_change_color(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_lock_color(struct wmOperatorType *ot);
@@ -234,30 +373,15 @@ void GPENCIL_OT_stroke_cyclical_set(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_join(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_flip(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_subdivide(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_simplify(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_simplify_fixed(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_separate(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_split(struct wmOperatorType *ot);
-void GPENCIL_OT_brush_add(struct wmOperatorType *ot);
-void GPENCIL_OT_brush_remove(struct wmOperatorType *ot);
-void GPENCIL_OT_brush_change(struct wmOperatorType *ot);
-void GPENCIL_OT_brush_move(struct wmOperatorType *ot);
void GPENCIL_OT_brush_presets_create(struct wmOperatorType *ot);
-void GPENCIL_OT_brush_copy(struct wmOperatorType *ot);
void GPENCIL_OT_brush_select(struct wmOperatorType *ot);
-void GPENCIL_OT_palette_add(struct wmOperatorType *ot);
-void GPENCIL_OT_palette_remove(struct wmOperatorType *ot);
-void GPENCIL_OT_palette_change(struct wmOperatorType *ot);
-void GPENCIL_OT_palette_lock_layer(struct wmOperatorType *ot);
-
-void GPENCIL_OT_palettecolor_add(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_remove(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_isolate(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_hide(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_reveal(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_lock_all(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_unlock_all(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_move(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_select(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_copy(struct wmOperatorType *ot);
+void GPENCIL_OT_sculpt_select(struct wmOperatorType *ot);
/* undo stack ---------- */
@@ -271,6 +395,30 @@ void GPENCIL_OT_interpolate(struct wmOperatorType *ot);
void GPENCIL_OT_interpolate_sequence(struct wmOperatorType *ot);
void GPENCIL_OT_interpolate_reverse(struct wmOperatorType *ot);
+/* primitives ---------- */
+
+void GPENCIL_OT_primitive(struct wmOperatorType *ot);
+
+/* vertex groups ------------ */
+void GPENCIL_OT_vertex_group_assign(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_group_remove_from(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_group_select(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_group_deselect(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_group_invert(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_group_smooth(struct wmOperatorType *ot);
+
+/* color handle */
+void GPENCIL_OT_lock_layer(struct wmOperatorType *ot);
+void GPENCIL_OT_color_isolate(struct wmOperatorType *ot);
+void GPENCIL_OT_color_hide(struct wmOperatorType *ot);
+void GPENCIL_OT_color_reveal(struct wmOperatorType *ot);
+void GPENCIL_OT_color_lock_all(struct wmOperatorType *ot);
+void GPENCIL_OT_color_unlock_all(struct wmOperatorType *ot);
+void GPENCIL_OT_color_select(struct wmOperatorType *ot);
+
+/* convert old 2.7 files to 2.8 */
+void GPENCIL_OT_convert_old_files(struct wmOperatorType *ot);
+
/* ****************************************************** */
/* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */
@@ -331,24 +479,37 @@ typedef enum ACTCONT_TYPES {
*/
#define GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) \
{ \
+ Depsgraph *depsgraph_ = CTX_data_depsgraph(C); \
+ Object *obact_ = CTX_data_active_object(C); \
+ bGPdata *gpd_ = CTX_data_gpencil_data(C); \
+ bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \
CTX_DATA_BEGIN(C, bGPDlayer*, gpl, editable_gpencil_layers) \
{ \
- if (gpl->actframe == NULL) \
- continue; \
- /* calculate difference matrix if parent object */ \
- float diff_mat[4][4]; \
- ED_gpencil_parent_location(gpl, diff_mat); \
- /* loop over strokes */ \
- for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) { \
- /* 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(gpl, gps) == false) \
- continue; \
- /* ... Do Stuff With Strokes ... */
+ 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))) { \
+ /* calculate difference matrix */ \
+ float diff_mat[4][4]; \
+ ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, diff_mat); \
+ /* loop over strokes */ \
+ 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; \
+ /* check if the color is editable */ \
+ if (ED_gpencil_stroke_color_use(obact_, gpl, gps) == false) \
+ continue; \
+ /* ... Do Stuff With Strokes ... */
#define GP_EDITABLE_STROKES_END \
+ } \
+ } \
+ if (!is_multiedit) { \
+ break; \
+ } \
} \
} \
CTX_DATA_END; \
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index cc30d7ec266..6541e9f012a 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -47,6 +47,7 @@
#include "DNA_color_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -60,6 +61,7 @@
#include "BKE_library.h"
#include "BKE_report.h"
#include "BKE_screen.h"
+#include "BKE_deform.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -79,6 +81,9 @@
#include "ED_view3d.h"
#include "ED_space_api.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "gpencil_intern.h"
/* ************************************************ */
@@ -108,11 +113,13 @@ static bool gpencil_view3d_poll(bContext *C)
static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor)
{
bGPDspoint *prev, *pt, *next;
+ MDeformVert *dvert;
/* update points */
for (int i = 0; i < new_stroke->totpoints; i++) {
prev = &gps_from->points[i];
pt = &new_stroke->points[i];
+ dvert = &new_stroke->dvert[i];
next = &gps_to->points[i];
/* Interpolate all values */
@@ -120,6 +127,9 @@ static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_t
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);
+
+ dvert->totweight = 0;
+ dvert->dw = NULL;
}
}
@@ -128,6 +138,7 @@ static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_t
/* 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;
@@ -156,12 +167,14 @@ static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
}
}
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
}
/* Helper: Verify valid strokes for interpolation */
static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd)
{
+ Object *ob = CTX_data_active_object(C);
ToolSettings *ts = CTX_data_tool_settings(C);
eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag;
@@ -190,7 +203,7 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) {
continue;
}
@@ -213,6 +226,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
bGPdata *gpd = tgpi->gpd;
bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
bGPDframe *actframe = active_gpl->actframe;
+ Object *ob = CTX_data_active_object(C);
/* save initial factor for active layer to define shift limits */
tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) / (actframe->next->framenum - actframe->framenum + 1);
@@ -255,7 +269,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
bGPDstroke *gps_to;
int fFrame;
- bGPDstroke *new_stroke;
+ bGPDstroke *new_stroke = NULL;
bool valid = true;
@@ -269,7 +283,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) {
+ if (ED_gpencil_stroke_color_use(ob, tgpil->gpl, gps_from) == false) {
valid = false;
}
@@ -281,16 +295,13 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
}
/* create new stroke */
- new_stroke = MEM_dupallocN(gps_from);
- new_stroke->points = MEM_dupallocN(gps_from->points);
- new_stroke->triangles = MEM_dupallocN(gps_from->triangles);
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ new_stroke = BKE_gpencil_stroke_duplicate(gps_from);
if (valid) {
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
if (gps_from->totpoints > gps_to->totpoints) {
new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
+ 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_CACHES;
@@ -302,6 +313,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
/* need an empty stroke to keep index correct for lookup, but resize to smallest size */
new_stroke->totpoints = 0;
new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points));
+ 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_CACHES;
@@ -317,17 +329,17 @@ 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 *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+static void gpencil_interpolate_draw_screen(const struct bContext *C, ARegion *UNUSED(ar), void *arg)
{
tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
- ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL);
+ 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 *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+static void gpencil_interpolate_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg)
{
tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
- ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW);
+ ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_VIEW);
}
/* ----------------------- */
@@ -392,6 +404,7 @@ 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) {
@@ -416,6 +429,7 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
BLI_freelistN(&tgpi->ilayers);
MEM_freeN(tgpi);
}
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
/* clear pointer */
@@ -483,9 +497,10 @@ static int gpencil_interpolate_init(bContext *C, wmOperator *op)
static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
wmWindow *win = CTX_wm_window(C);
- Scene *scene = CTX_data_scene(C);
bGPdata *gpd = CTX_data_gpencil_data(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
bGPDframe *actframe = gpl->actframe;
tGPDinterpolate *tgpi = NULL;
@@ -496,7 +511,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
}
/* cannot interpolate in extremes */
- if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) {
+ if (ELEM(cfra_eval, actframe->framenum, actframe->next->framenum)) {
BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames");
return OPERATOR_CANCELLED;
}
@@ -529,6 +544,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
/* update shift indicator in header */
gpencil_interpolate_status_indicators(C, tgpi);
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
/* add a modal handler for this operator */
@@ -571,6 +587,8 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent
/* 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);
+ 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_CACHES;
BLI_addtail(&gpf_dst->strokes, gps_dst);
@@ -902,8 +920,11 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
bGPDframe *actframe = active_gpl->actframe;
- Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate;
eGP_Interpolate_SettingsFlag flag = ipo_settings->flag;
@@ -913,7 +934,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* cannot interpolate in extremes */
- if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) {
+ if (ELEM(cfra_eval, actframe->framenum, actframe->next->framenum)) {
BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames");
return OPERATOR_CANCELLED;
}
@@ -961,7 +982,7 @@ 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;
+ bGPDstroke *new_stroke = NULL;
/* only selected */
if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
@@ -972,7 +993,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) {
continue;
}
@@ -990,15 +1011,15 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
}
/* create new stroke */
- new_stroke = MEM_dupallocN(gps_from);
- new_stroke->points = MEM_dupallocN(gps_from->points);
- new_stroke->triangles = MEM_dupallocN(gps_from->triangles);
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ new_stroke = BKE_gpencil_stroke_duplicate(gps_from);
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
if (gps_from->totpoints > gps_to->totpoints) {
+ /* free weights of removed points */
+ BKE_defvert_array_free_elems(gps_from->dvert + gps_to->totpoints, gps_from->totpoints - gps_to->totpoints);
+
new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
+ 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_CACHES;
@@ -1014,6 +1035,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1055,6 +1077,8 @@ static bool gpencil_interpolate_reverse_poll(bContext *C)
static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op))
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
/* Go through each layer, deleting the breakdowns around the current frame,
* but only if there is a keyframe nearby to stop at
*/
@@ -1123,6 +1147,7 @@ static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_END;
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/gpencil/gpencil_old.c b/source/blender/editors/gpencil/gpencil_old.c
new file mode 100644
index 00000000000..b7af1c80d4c
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_old.c
@@ -0,0 +1,219 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2018, Blender Foundation,
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Use deprecated data to convert old 2.7x files
+ */
+
+/** \file blender/editors/gpencil/gpencil_old.c
+ * \ingroup edgpencil
+ */
+
+ /* allow to use deprecated functionality */
+#define DNA_DEPRECATED_ALLOW
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_main.h"
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_object.h"
+#include "BKE_material.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_gpencil.h"
+
+#include "gpencil_intern.h"
+
+ /* Free all of a gp-colors */
+static void free_gpencil_colors(bGPDpalette *palette)
+{
+ /* error checking */
+ if (palette == NULL) {
+ return;
+ }
+
+ /* free colors */
+ BLI_freelistN(&palette->colors);
+}
+
+/* Free all of the gp-palettes and colors */
+static void free_palettes(ListBase *list)
+{
+ bGPDpalette *palette_next;
+
+ /* error checking */
+ if (list == NULL) {
+ return;
+ }
+
+ /* delete palettes */
+ for (bGPDpalette *palette = list->first; palette; palette = palette_next) {
+ palette_next = palette->next;
+ /* free palette colors */
+ free_gpencil_colors(palette);
+
+ MEM_freeN(palette);
+ }
+ BLI_listbase_clear(list);
+}
+
+/* ***************** Convert old 2.7 files to 2.8 ************************ */
+static bool gpencil_convert_old_files_poll(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ return (int) (scene->gpd != NULL);
+}
+
+static int gpencil_convert_old_files_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ /* Convert grease pencil scene datablock to GP object */
+ if ((scene->gpd) && (view_layer != NULL)) {
+ Object *ob;
+ ob = BKE_object_add_for_data(bmain, view_layer, OB_GPENCIL, "GP_Scene", &scene->gpd->id, false);
+ zero_v3(ob->loc);
+
+ Paint *paint = BKE_brush_get_gpencil_paint(ts);
+ /* if not exist, create a new one */
+ if (paint->brush == NULL) {
+ /* create new brushes */
+ BKE_brush_gpencil_presets(C);
+ }
+
+ /* convert grease pencil palettes (version >= 2.78) to materials and weights */
+ bGPdata *gpd = scene->gpd;
+ for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
+ for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+
+ /* create material slot */
+ BKE_object_material_slot_add(bmain, ob);
+ Material *ma = BKE_material_add_gpencil(bmain, palcolor->info);
+ assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_EXISTING);
+
+ /* copy color settings */
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ copy_v4_v4(gp_style->stroke_rgba, palcolor->color);
+ copy_v4_v4(gp_style->fill_rgba, palcolor->fill);
+ gp_style->flag = palcolor->flag;
+
+ /* 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) {
+ if ((gps->colorname[0] != '\0') &&
+ (STREQ(gps->colorname, palcolor->info)))
+ {
+ gps->mat_nr = ob->totcol - 1;
+ gps->colorname[0] = '\0';
+ /* create weights array */
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* free palettes */
+ free_palettes(&gpd->palettes);
+
+ /* disable all GP modes */
+ ED_gpencil_setup_modes(C, gpd, 0);
+
+ /* set cache as dirty */
+ BKE_gpencil_batch_cache_dirty(ob->data);
+
+ scene->gpd = NULL;
+ }
+
+#if 0 /* GPXX */
+ /* Handle object-linked grease pencil datablocks */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->gpd) {
+ if (ob->type == OB_GPENCIL) {
+ /* GP Object - remap the links */
+ ob->data = ob->gpd;
+ ob->gpd = NULL;
+ }
+ else if (ob->type == OB_EMPTY) {
+ /* Empty with GP data - This should be able to be converted
+ * to a GP object with little data loss
+ */
+ ob->data = ob->gpd;
+ ob->gpd = NULL;
+ ob->type = OB_GPENCIL;
+ }
+ else {
+ /* FIXME: What to do in this case?
+ *
+ * We cannot create new objects for these, as we don't have a scene & scene layer
+ * to put them into from here...
+ */
+ printf("WARNING: Old Grease Pencil data ('%s') still exists on Object '%s'\n",
+ ob->gpd->id.name + 2, ob->id.name + 2);
+ }
+ }
+ }
+#endif
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_convert_old_files(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Convert 2.7 Grease Pencil File";
+ ot->idname = "GPENCIL_OT_convert_old_files";
+ ot->description = "Convert 2.7x grease pencil files to 2.8";
+
+ /* callbacks */
+ ot->exec = gpencil_convert_old_files_exec;
+ ot->poll = gpencil_convert_old_files_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 3f114a4dd4a..991bfb622b7 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -35,8 +35,14 @@
#include "BLI_sys_types.h"
#include "BKE_context.h"
+#include "BKE_brush.h"
+#include "BKE_gpencil.h"
+#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -52,7 +58,7 @@
/* ****************************************** */
/* Grease Pencil Keymaps */
-/* Generic Drawing Keymap */
+/* Generic Drawing Keymap - Annotations */
static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil", 0, 0);
@@ -60,36 +66,22 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
/* Draw --------------------------------------- */
/* draw */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, 0, DKEY);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_annotate", LEFTMOUSE, KM_PRESS, 0, DKEY);
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW);
RNA_boolean_set(kmi->ptr, "wait_for_input", false);
/* draw - straight lines */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_CTRL, DKEY);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_annotate", LEFTMOUSE, KM_PRESS, KM_ALT, DKEY);
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_STRAIGHT);
RNA_boolean_set(kmi->ptr, "wait_for_input", false);
/* draw - poly lines */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, KM_CTRL, DKEY);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_annotate", LEFTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, DKEY);
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_POLY);
RNA_boolean_set(kmi->ptr, "wait_for_input", false);
/* erase */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, 0, DKEY);
- RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-
- /* Tablet Mappings for Drawing ------------------ */
- /* For now, only support direct drawing using the eraser, as most users using a tablet
- * may still want to use that as their primary pointing device!
- */
-#if 0
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_STYLUS, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-#endif
-
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_ERASER, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_annotate", RIGHTMOUSE, KM_PRESS, 0, DKEY);
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
RNA_boolean_set(kmi->ptr, "wait_for_input", false);
@@ -121,67 +113,85 @@ static bool gp_stroke_editmode_poll(bContext *C)
return (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE));
}
-/* Stroke Editing Keymap - Only when editmode is enabled */
-static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
+/* Poll callback for stroke painting mode */
+static bool gp_stroke_paintmode_poll(bContext *C)
{
- wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Edit Mode", 0, 0);
- wmKeyMapItem *kmi;
-
- /* set poll callback - so that this keymap only gets enabled when stroke editmode is enabled */
- keymap->poll = gp_stroke_editmode_poll;
-
- /* ----------------------------------------------- */
-
- /* Exit EditMode */
- WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, 0);
-
- /* Pie Menu - For settings/tools easy access */
- WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_sculpt", EKEY, KM_PRESS, 0, DKEY);
-
- /* Brush Settings */
- /* NOTE: We cannot expose these in the standard keymap, as they will interfere with regular hotkeys
- * in other modes. However, when we are dealing with Stroke Edit Mode, we know for certain
- * that the only data being edited is that of the Grease Pencil strokes
- */
-
- /* CTRL + FKEY = Eraser Radius */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path_primary", "user_preferences.edit.grease_pencil_eraser_radius");
-
- /* Interpolation */
- WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate", EKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate_sequence", EKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ /* TODO: limit this to mode, but review 2D editors */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE));
+}
- /* Sculpting ------------------------------------- */
+/* Poll callback for stroke painting (draw brush) */
+static bool gp_stroke_paintmode_draw_poll(bContext *C)
+{
+ /* TODO: limit this to mode, but review 2D editors */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Brush *brush = BKE_brush_getactive_gpencil(ts);
+ return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE) && (brush)
+ && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_DRAW));
+}
- /* Brush-Based Editing:
- * EKEY + LMB = Single stroke, draw immediately
- * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc.
- *
- * For the modal version, use D+E -> Sculpt
- */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, EKEY);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+/* Poll callback for stroke painting (erase brush) */
+static bool gp_stroke_paintmode_erase_poll(bContext *C)
+{
+ /* TODO: limit this to mode, but review 2D editors */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Brush *brush = BKE_brush_getactive_gpencil(ts);
+ return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE) && (brush)
+ && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE));
+}
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, EKEY);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
- /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/
+/* Poll callback for stroke painting (fill) */
+static bool gp_stroke_paintmode_fill_poll(bContext *C)
+{
+ /* TODO: limit this to mode, but review 2D editors */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Brush *brush = BKE_brush_getactive_gpencil(ts);
+ return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE) && (brush)
+ && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_FILL));
+}
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, EKEY);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
- /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/
+/* Poll callback for stroke sculpting mode */
+static bool gp_stroke_sculptmode_poll(bContext *C)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Object *ob = CTX_data_active_object(C);
+ ScrArea *sa = CTX_wm_area(C);
+
+ /* if not gpencil object and not view3d, need sculpt keys if edit mode */
+ if (sa->spacetype != SPACE_VIEW3D) {
+ 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 0;
+}
+/* Poll callback for stroke weight paint mode */
+static bool gp_stroke_weightmode_poll(bContext *C)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Object *ob = CTX_data_active_object(C);
- /* Shift-FKEY = Sculpt Strength */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength");
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ return (gpd && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE));
+ }
- /* FKEY = Sculpt Brush Size */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size");
+ return 0;
+}
+static void ed_keymap_gpencil_selection(wmKeyMap *keymap)
+{
+ wmKeyMapItem *kmi;
- /* Selection ------------------------------------- */
/* select all */
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", AKEY, KM_PRESS, 0, 0);
RNA_enum_set(kmi->ptr, "action", SEL_SELECT);
@@ -204,17 +214,14 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
RNA_boolean_set(kmi->ptr, "deselect", true);
/* In the Node Editor, lasso select needs ALT modifier too (as somehow CTRL+LMB drag gets taken for "cut" quite early)
- * There probably isn't too much harm adding this for other editors too as part of standard GP editing keymap. This hotkey
- * combo doesn't seem to see much use under standard scenarios?
- */
+ * There probably isn't too much harm adding this for other editors too as part of standard GP editing keymap. This hotkey
+ * combo doesn't seem to see much use under standard scenarios?
+ */
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "deselect", false);
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL | KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "deselect", true);
- /* normal select */
- WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
-
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", true);
RNA_boolean_set(kmi->ptr, "toggle", true);
@@ -223,11 +230,18 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "entire_strokes", true);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "entire_strokes", true);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+
/* select linked */
/* NOTE: While LKEY is redundant, not having it breaks the mode illusion too much */
WM_keymap_add_item(keymap, "GPENCIL_OT_select_linked", LKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
+ /* select alternate */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_select_alternate", LKEY, KM_PRESS, KM_SHIFT, 0);
+
/* select grouped */
WM_keymap_add_item(keymap, "GPENCIL_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0);
@@ -235,6 +249,102 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "GPENCIL_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
+}
+
+static void ed_keymap_gpencil_sculpt(wmKeyMap *keymap)
+{
+ wmKeyMapItem *kmi;
+
+ /* Pie Menu - For settings/tools easy access */
+ WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_sculpt", EKEY, KM_PRESS, 0, DKEY);
+
+ /* Sculpting ------------------------------------- */
+
+ /* Brush-Based Editing:
+ * EKEY + LMB = Single stroke, draw immediately
+ * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc.
+ *
+ * For the modal version, use D+E -> Sculpt
+ */
+ /* GPXX: disabled to make toolsystem works */
+ //kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, 0);
+ //RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+ RNA_boolean_set(kmi->ptr, "keep_brush", true);
+ /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+ RNA_boolean_set(kmi->ptr, "keep_brush", true);
+ /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/
+
+ /* Shift-FKEY = Sculpt Strength */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength");
+
+ /* FKEY = Sculpt Brush Size */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size");
+
+ /* menu sculpt specials */
+ WM_keymap_add_menu(keymap, "GPENCIL_MT_gpencil_sculpt_specials", WKEY, KM_PRESS, 0, 0);
+}
+
+static void ed_keymap_gpencil_weight(wmKeyMap *keymap)
+{
+ wmKeyMapItem *kmi;
+
+
+ /* Brush-Based Editing:
+ * EKEY + LMB = Single stroke, draw immediately
+ * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc.
+ *
+ * For the modal version, use D+E -> Sculpt
+ */
+ /* GPXX: disabled to make toolsystem works */
+ //kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, 0);
+ //RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+ RNA_boolean_set(kmi->ptr, "keep_brush", true);
+ /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+ RNA_boolean_set(kmi->ptr, "keep_brush", true);
+ /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/
+}
+
+/* Stroke Editing Keymap - Only when editmode is enabled */
+static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Edit Mode", 0, 0);
+ wmKeyMapItem *kmi;
+
+ /* set poll callback - so that this keymap only gets enabled when stroke editmode is enabled */
+ keymap->poll = gp_stroke_editmode_poll;
+
+ /* ----------------------------------------------- */
+
+ /* Brush Settings */
+ /* NOTE: We cannot expose these in the standard keymap, as they will interfere with regular hotkeys
+ * in other modes. However, when we are dealing with Stroke Edit Mode, we know for certain
+ * that the only data being edited is that of the Grease Pencil strokes
+ */
+
+ /* Interpolation */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate", EKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate_sequence", EKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+
+ /* normal select */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
+
+ /* Selection */
+ ed_keymap_gpencil_selection(keymap);
+
/* Editing ----------------------------------------- */
/* duplicate and move selected points */
@@ -253,6 +363,12 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
/* menu edit specials */
WM_keymap_add_menu(keymap, "GPENCIL_MT_gpencil_edit_specials", WKEY, KM_PRESS, 0, 0);
+ /* menu separate */
+ WM_keymap_add_menu(keymap, "GPENCIL_MT_separate", PKEY, KM_PRESS, 0, 0);
+
+ /* split strokes */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_stroke_split", VKEY, KM_PRESS, 0, 0);
+
/* join strokes */
WM_keymap_add_item(keymap, "GPENCIL_OT_stroke_join", JKEY, KM_PRESS, KM_CTRL, 0);
@@ -271,7 +387,6 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
/* snap */
WM_keymap_add_menu(keymap, "GPENCIL_MT_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
-
/* convert to geometry */
WM_keymap_add_item(keymap, "GPENCIL_OT_convert", CKEY, KM_PRESS, KM_ALT, 0);
@@ -288,6 +403,13 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "GPENCIL_OT_selection_opacity_toggle", HKEY, KM_PRESS, KM_CTRL, 0);
+ /* toogle multiedit support */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "toggle_visibility", 0);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "toggle_visibility", 1);
+
/* Isolate Layer */
WM_keymap_add_item(keymap, "GPENCIL_OT_layer_isolate", PADASTERKEY, KM_PRESS, 0, 0);
@@ -317,28 +439,246 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
/* Proportional Editing */
ED_keymap_proportional_cycle(keyconf, keymap);
ED_keymap_proportional_editmode(keyconf, keymap, true);
+
+ /* menu - add GP object (3d view only) */
+ WM_keymap_add_item(keymap, "OBJECT_OT_gpencil_add", AKEY, KM_PRESS, KM_SHIFT, 0);
+
+ /* menu vertex group */
+ WM_keymap_add_menu(keymap, "GPENCIL_MT_gpencil_vertex_group", GKEY, KM_PRESS, KM_CTRL, 0);
+
+ /* toggle edit mode */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, 0);
+}
+
+/* keys for draw with a drawing brush (no fill) */
+static void ed_keymap_gpencil_painting_draw(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Paint (Draw brush)", 0, 0);
+ wmKeyMapItem *kmi;
+
+ /* set poll callback */
+ keymap->poll = gp_stroke_paintmode_draw_poll;
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ /* draw - straight lines */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_ALT, 0);
+ RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_STRAIGHT);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ /* draw - poly lines */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0);
+ RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_POLY);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ /* erase */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ /* Tablet Mappings for Drawing ------------------ */
+ /* For now, only support direct drawing using the eraser, as most users using a tablet
+ * may still want to use that as their primary pointing device!
+ */
+#if 0
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_STYLUS, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+#endif
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_ERASER, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ /* Selection (used by eraser) */
+ /* border select */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_select_border", BKEY, KM_PRESS, 0, 0);
+
+ /* lasso select */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_ALT, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", false);
+}
+
+/* keys for draw with a eraser brush (erase) */
+static void ed_keymap_gpencil_painting_erase(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Paint (Erase)", 0, 0);
+ wmKeyMapItem *kmi;
+
+ /* set poll callback */
+ keymap->poll = gp_stroke_paintmode_erase_poll;
+
+ /* erase */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_ERASER, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ /* Selection (used by eraser) */
+ /* border select */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_select_border", BKEY, KM_PRESS, 0, 0);
+
+ /* lasso select */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_ALT, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", false);
+}
+
+/* keys for draw with a fill brush */
+static void ed_keymap_gpencil_painting_fill(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Paint (Fill)", 0, 0);
+ wmKeyMapItem *kmi;
+
+ /* set poll callback */
+ keymap->poll = gp_stroke_paintmode_fill_poll;
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_fill", LEFTMOUSE, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "on_back", false);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_fill", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "on_back", true);
+
+ /* if press alternative key, the brush now it's for drawing areas */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+ /* disable straight lines */
+ RNA_boolean_set(kmi->ptr, "disable_straight", true);
+
+ /* if press alternative key, the brush now it's for drawing lines */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_ALT, 0);
+ RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+ /* disable straight lines */
+ RNA_boolean_set(kmi->ptr, "disable_straight", true);
+ /* enable special stroke with no fill flag */
+ RNA_boolean_set(kmi->ptr, "disable_fill", true);
+}
+
+/* Stroke Painting Keymap - Only when paintmode is enabled */
+static void ed_keymap_gpencil_painting(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Paint Mode", 0, 0);
+ wmKeyMapItem *kmi;
+
+ /* set poll callback - so that this keymap only gets enabled when stroke paintmode is enabled */
+ keymap->poll = gp_stroke_paintmode_poll;
+
+ /* FKEY = Brush Size */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_paint.brush.size");
+
+ /* CTRL + FKEY = Eraser Radius */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_string_set(kmi->ptr, "data_path_primary", "user_preferences.edit.grease_pencil_eraser_radius");
+
+ /* menu draw specials */
+ WM_keymap_add_menu(keymap, "GPENCIL_MT_gpencil_draw_specials", WKEY, KM_PRESS, 0, 0);
+
+ /* menu draw delete */
+ WM_keymap_add_menu(keymap, "GPENCIL_MT_gpencil_draw_delete", XKEY, KM_PRESS, 0, 0);
+
}
+/* Stroke Sculpting Keymap - Only when sculptmode is enabled */
+static void ed_keymap_gpencil_sculpting(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Sculpt Mode", 0, 0);
+ wmKeyMapItem *kmi;
+
+ /* set poll callback - so that this keymap only gets enabled when stroke sculptmode is enabled */
+ keymap->poll = gp_stroke_sculptmode_poll;
+
+ /* Selection */
+ ed_keymap_gpencil_selection(keymap);
+
+ /* sculpt */
+ ed_keymap_gpencil_sculpt(keymap);
+
+ /* toogle multiedit support */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "toggle_visibility", 0);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "toggle_visibility", 1);
+
+}
+
+/* Stroke Weight Paint Keymap - Only when weight is enabled */
+static void ed_keymap_gpencil_weightpainting(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Weight Mode", 0, 0);
+ wmKeyMapItem *kmi;
+
+ /* set poll callback - so that this keymap only gets enabled when stroke sculptmode is enabled */
+ keymap->poll = gp_stroke_weightmode_poll;
+
+ /* Selection */
+ ed_keymap_gpencil_selection(keymap);
+
+ /* sculpt */
+ ed_keymap_gpencil_weight(keymap);
+
+ /* Shift-FKEY = Sculpt Strength */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.weight_brush.strength");
+
+ /* FKEY = Sculpt Brush Size */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.weight_brush.size");
+
+ /* toogle multiedit support */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "toggle_visibility", 0);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "toggle_visibility", 1);
+
+}
/* ==================== */
void ED_keymap_gpencil(wmKeyConfig *keyconf)
{
ed_keymap_gpencil_general(keyconf);
ed_keymap_gpencil_editing(keyconf);
+ ed_keymap_gpencil_painting(keyconf);
+ ed_keymap_gpencil_painting_draw(keyconf);
+ ed_keymap_gpencil_painting_erase(keyconf);
+ ed_keymap_gpencil_painting_fill(keyconf);
+ ed_keymap_gpencil_sculpting(keyconf);
+ ed_keymap_gpencil_weightpainting(keyconf);
}
/* ****************************************** */
void ED_operatortypes_gpencil(void)
{
+ /* Annotations -------------------- */
+
+ WM_operatortype_append(GPENCIL_OT_annotate);
+
/* Drawing ----------------------- */
WM_operatortype_append(GPENCIL_OT_draw);
+ WM_operatortype_append(GPENCIL_OT_fill);
/* Editing (Strokes) ------------ */
WM_operatortype_append(GPENCIL_OT_editmode_toggle);
+ 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_selection_opacity_toggle);
+ WM_operatortype_append(GPENCIL_OT_multiedit_toggle);
WM_operatortype_append(GPENCIL_OT_select);
WM_operatortype_append(GPENCIL_OT_select_all);
@@ -352,6 +692,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_select_less);
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_duplicate);
WM_operatortype_append(GPENCIL_OT_delete);
@@ -391,6 +732,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
+ WM_operatortype_append(GPENCIL_OT_frame_duplicate);
+ WM_operatortype_append(GPENCIL_OT_frame_clean_fill);
WM_operatortype_append(GPENCIL_OT_convert);
@@ -402,36 +745,46 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_stroke_join);
WM_operatortype_append(GPENCIL_OT_stroke_flip);
WM_operatortype_append(GPENCIL_OT_stroke_subdivide);
+ WM_operatortype_append(GPENCIL_OT_stroke_simplify);
+ WM_operatortype_append(GPENCIL_OT_stroke_simplify_fixed);
+ WM_operatortype_append(GPENCIL_OT_stroke_separate);
+ WM_operatortype_append(GPENCIL_OT_stroke_split);
- WM_operatortype_append(GPENCIL_OT_palette_add);
- WM_operatortype_append(GPENCIL_OT_palette_remove);
- WM_operatortype_append(GPENCIL_OT_palette_change);
- WM_operatortype_append(GPENCIL_OT_palette_lock_layer);
- WM_operatortype_append(GPENCIL_OT_palettecolor_add);
- WM_operatortype_append(GPENCIL_OT_palettecolor_remove);
- WM_operatortype_append(GPENCIL_OT_palettecolor_isolate);
- WM_operatortype_append(GPENCIL_OT_palettecolor_hide);
- WM_operatortype_append(GPENCIL_OT_palettecolor_reveal);
- WM_operatortype_append(GPENCIL_OT_palettecolor_lock_all);
- WM_operatortype_append(GPENCIL_OT_palettecolor_unlock_all);
- WM_operatortype_append(GPENCIL_OT_palettecolor_move);
- WM_operatortype_append(GPENCIL_OT_palettecolor_select);
- WM_operatortype_append(GPENCIL_OT_palettecolor_copy);
-
- WM_operatortype_append(GPENCIL_OT_brush_add);
- WM_operatortype_append(GPENCIL_OT_brush_remove);
- WM_operatortype_append(GPENCIL_OT_brush_change);
- WM_operatortype_append(GPENCIL_OT_brush_move);
WM_operatortype_append(GPENCIL_OT_brush_presets_create);
- WM_operatortype_append(GPENCIL_OT_brush_copy);
WM_operatortype_append(GPENCIL_OT_brush_select);
+ WM_operatortype_append(GPENCIL_OT_sculpt_select);
+
+ /* vertex groups */
+ WM_operatortype_append(GPENCIL_OT_vertex_group_assign);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_remove_from);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_select);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_deselect);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_invert);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_smooth);
+
+ /* color handle */
+ WM_operatortype_append(GPENCIL_OT_lock_layer);
+ WM_operatortype_append(GPENCIL_OT_color_isolate);
+ WM_operatortype_append(GPENCIL_OT_color_hide);
+ WM_operatortype_append(GPENCIL_OT_color_reveal);
+ WM_operatortype_append(GPENCIL_OT_color_lock_all);
+ WM_operatortype_append(GPENCIL_OT_color_unlock_all);
+ WM_operatortype_append(GPENCIL_OT_color_select);
+
/* Editing (Time) --------------- */
/* Interpolation */
WM_operatortype_append(GPENCIL_OT_interpolate);
WM_operatortype_append(GPENCIL_OT_interpolate_sequence);
WM_operatortype_append(GPENCIL_OT_interpolate_reverse);
+
+ /* Primitives */
+ WM_operatortype_append(GPENCIL_OT_primitive);
+
+ /* convert old 2.7 files to 2.8 */
+ WM_operatortype_append(GPENCIL_OT_convert_old_files);
+
}
void ED_operatormacros_gpencil(void)
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 789e9865ae4..995ab91ff8b 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -46,26 +46,34 @@
#include "PIL_time.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_material_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_windowmanager_types.h"
+
#include "BKE_colortools.h"
+#include "BKE_main.h"
+#include "BKE_brush.h"
+#include "BKE_paint.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_main.h"
#include "BKE_paint.h"
#include "BKE_report.h"
+#include "BKE_layer.h"
+#include "BKE_material.h"
#include "BKE_screen.h"
#include "BKE_tracking.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_windowmanager_types.h"
-
#include "UI_view2d.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
+#include "ED_object.h"
#include "ED_view3d.h"
#include "ED_clip.h"
@@ -82,6 +90,7 @@
#include "WM_types.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "gpencil_intern.h"
@@ -110,6 +119,8 @@ typedef enum eGPencil_PaintFlags {
GP_PAINTFLAG_STROKEADDED = (1 << 1),
GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
GP_PAINTFLAG_SELECTMASK = (1 << 3),
+ GP_PAINTFLAG_HARD_ERASER = (1 << 4),
+ GP_PAINTFLAG_STROKE_ERASER = (1 << 5),
} eGPencil_PaintFlags;
@@ -117,10 +128,13 @@ typedef enum eGPencil_PaintFlags {
* "p" = op->customdata
*/
typedef struct tGPsdata {
- Main *bmain;
+ bContext *C;
+
+ Main *bmain; /* main database pointer */
Scene *scene; /* current scene from context */
struct Depsgraph *depsgraph;
+ Object *ob; /* current object */
wmWindow *win; /* window where painting originated */
ScrArea *sa; /* area where painting originated */
ARegion *ar; /* region where painting originated */
@@ -165,14 +179,23 @@ typedef struct tGPsdata {
void *erasercursor; /* radial cursor data for drawing eraser */
- bGPDpalettecolor *palettecolor; /* current palette color */
- bGPDbrush *brush; /* current drawing brush */
+ /* mat settings are only used for 3D view */
+ Material *material; /* current material */
+
+ Brush *brush; /* current drawing brush */
+ Brush *eraser; /* default eraser brush */
short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */
int lock_axis; /* lock drawing to one axis */
+ bool disable_fill; /* the stroke is no fill mode */
RNG *rng;
short keymodifier; /* key used for invoking the operator */
+ short shift; /* shift modifier flag */
+
+ float totpixlen; /* size in pixels for uv calculation */
+
+ ReportList *reports;
} tGPsdata;
/* ------ */
@@ -183,6 +206,14 @@ typedef struct tGPsdata {
/* minimum length of new segment before new point can be added */
#define MIN_EUCLIDEAN_PX (U.gp_euclideandist)
+static void gp_update_cache(bGPdata *gpd)
+{
+ if (gpd) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
+}
+
static bool gp_stroke_added_check(tGPsdata *p)
{
return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED);
@@ -192,6 +223,9 @@ static void gp_stroke_added_enable(tGPsdata *p)
{
BLI_assert(p->gpf->strokes.last != NULL);
p->flags |= GP_PAINTFLAG_STROKEADDED;
+
+ /* drawing batch cache is dirty now */
+ gp_update_cache(p->gpd);
}
/* ------ */
@@ -206,30 +240,42 @@ static void gp_session_validatebuffer(tGPsdata *p);
static bool gpencil_draw_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) {
- /* check if Grease Pencil isn't already running */
- if (ED_gpencil_session_active() == 0)
- return 1;
- else
- CTX_wm_operator_poll_msg_set(C, "Grease Pencil operator is already active");
+ ScrArea *sa = CTX_wm_area(C);
+ if (!ELEM(sa->spacetype, SPACE_VIEW3D)) {
+ /* check if current context can support GPencil data */
+ if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
+ /* check if Grease Pencil isn't already running */
+ if (ED_gpencil_session_active() == 0)
+ return 1;
+ else
+ CTX_wm_operator_poll_msg_set(C, "Grease Pencil operator is already active");
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
+ }
+ return 0;
}
+ /* 3D Viewport */
else {
- CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
+ if (ED_gpencil_session_active() == 0) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
}
}
else {
CTX_wm_operator_poll_msg_set(C, "Active region not set");
+ return 0;
}
-
- return 0;
}
/* check if projecting strokes into 3d-geometry in the 3D-View */
static bool gpencil_project_check(tGPsdata *p)
{
bGPdata *gpd = p->gpd;
- return ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)));
+ return ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)));
}
/* ******************************************* */
@@ -241,38 +287,39 @@ static bool gpencil_project_check(tGPsdata *p)
static void gp_get_3d_reference(tGPsdata *p, float vec[3])
{
View3D *v3d = p->sa->spacedata.first;
- const float *fp = ED_view3d_cursor3d_get(p->scene, v3d)->location;
-
- /* the reference point used depends on the owner... */
-#if 0 /* XXX: disabled for now, since we can't draw relative to the owner yet */
+ Object *ob = NULL;
if (p->ownerPtr.type == &RNA_Object) {
- Object *ob = (Object *)p->ownerPtr.data;
-
- /* active Object
- * - use relative distance of 3D-cursor from object center
- */
- sub_v3_v3v3(vec, fp, ob->loc);
- }
- else
-#endif
- {
- /* use 3D-cursor */
- copy_v3_v3(vec, fp);
+ ob = (Object *)p->ownerPtr.data;
}
+ ED_gp_get_drawing_reference(v3d, p->scene, ob, p->gpl, *p->align_flag, vec);
}
/* Stroke Editing ---------------------------- */
-
/* check if the current mouse position is suitable for adding a new point */
static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2])
{
+ Brush *brush = p->brush;
int dx = abs(mval[0] - pmval[0]);
int dy = abs(mval[1] - pmval[1]);
+ brush->gpencil_settings->flag &= ~GP_BRUSH_STABILIZE_MOUSE_TEMP;
/* if buffer is empty, just let this go through (i.e. so that dots will work) */
- if (p->gpd->sbuffer_size == 0)
+ if (p->gpd->runtime.sbuffer_size == 0) {
return true;
-
+ }
+ /* if lazy mouse, check minimum distance */
+ else if (GPENCIL_LAZY_MODE(brush, p->shift)) {
+ brush->gpencil_settings->flag |= GP_BRUSH_STABILIZE_MOUSE_TEMP;
+ if ((dx * dx + dy * dy) > (brush->smooth_stroke_radius * brush->smooth_stroke_radius)) {
+ return true;
+ }
+ else {
+ /* If the mouse is moving within the radius of the last move,
+ * don't update the mouse position. This allows sharp turns. */
+ copy_v2_v2_int(p->mval, p->mvalo);
+ return false;
+ }
+ }
/* check if mouse moved at least certain distance on both axes (best case)
* - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand
*/
@@ -291,47 +338,17 @@ static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2])
return false;
}
-/* reproject the points of the stroke to a plane locked to axis to avoid stroke offset */
-static void gp_project_points_to_plane(RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis)
-{
- float plane_normal[3];
- float vn[3];
-
- float ray[3];
- float rpoint[3];
-
- /* normal vector for a plane locked to axis */
- zero_v3(plane_normal);
- plane_normal[axis] = 1.0f;
-
- /* Reproject the points in the plane */
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
-
- /* get a vector from the point with the current view direction of the viewport */
- ED_view3d_global_to_vector(rv3d, &pt->x, vn);
-
- /* calculate line extrem point to create a ray that cross the plane */
- mul_v3_fl(vn, -50.0f);
- add_v3_v3v3(ray, &pt->x, vn);
-
- /* if the line never intersect, the point is not changed */
- if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
- copy_v3_v3(&pt->x, rpoint);
- }
- }
-}
-
/* reproject stroke to plane locked to axis in 3d cursor location */
static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps)
{
bGPdata *gpd = p->gpd;
+ Object *obact = (Object *)p->ownerPtr.data;
+
float origin[3];
- float cursor[3];
RegionView3D *rv3d = p->ar->regiondata;
/* verify the stroke mode is CURSOR 3d space mode */
- if ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) == 0) {
+ if ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) == 0) {
return;
}
if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
@@ -341,12 +358,9 @@ static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps)
return;
}
- /* get 3d cursor and set origin for locked axis only. Uses axis-1 because the enum for XYZ start with 1 */
- gp_get_3d_reference(p, cursor);
- zero_v3(origin);
- origin[p->lock_axis - 1] = cursor[p->lock_axis - 1];
-
- gp_project_points_to_plane(rv3d, gps, origin, p->lock_axis - 1);
+ /* get drawing origin */
+ gp_get_3d_reference(p, origin);
+ ED_gp_project_stroke_to_plane(obact, rv3d, gps, origin, p->lock_axis - 1);
}
/* convert screen-coordinates to buffer-coordinates */
@@ -356,7 +370,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3]
bGPdata *gpd = p->gpd;
/* in 3d-space - pt->x/y/z are 3 side-by-side floats */
- if (gpd->sbuffer_sflag & GP_STROKE_3DSPACE) {
+ if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
if (gpencil_project_check(p) && (ED_view3d_autodist_simple(p->ar, mval, out, 0, depth))) {
/* projecting onto 3D-Geometry
* - nothing more needs to be done here, since view_autodist_simple() has already done it
@@ -365,7 +379,8 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3]
else {
float mval_prj[2];
float rvec[3], dvec[3];
- float mval_f[2] = {UNPACK2(mval)};
+ float mval_f[2];
+ copy_v2fl_v2i(mval_f, mval);
float zfac;
/* Current method just converts each point in screen-coordinates to
@@ -390,42 +405,23 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3]
}
}
}
-
- /* 2d - on 'canvas' (assume that p->v2d is set) */
- else if ((gpd->sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) {
- UI_view2d_region_to_view(p->v2d, mval[0], mval[1], &out[0], &out[1]);
- mul_v3_m4v3(out, p->imat, out);
- }
-
- /* 2d - relative to screen (viewport area) */
- else {
- if (p->subrect == NULL) { /* normal 3D view */
- out[0] = (float)(mval[0]) / (float)(p->ar->winx) * 100;
- out[1] = (float)(mval[1]) / (float)(p->ar->winy) * 100;
- }
- else { /* camera view, use subrect */
- out[0] = ((mval[0] - p->subrect->xmin) / BLI_rctf_size_x(p->subrect)) * 100;
- out[1] = ((mval[1] - p->subrect->ymin) / BLI_rctf_size_y(p->subrect)) * 100;
- }
- }
}
/* apply jitter to stroke */
-static void gp_brush_jitter(
- bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const int mval[2], int r_mval[2], RNG *rng)
+static void gp_brush_jitter(bGPdata *gpd, Brush *brush, tGPspoint *pt, const int mval[2], int r_mval[2], RNG *rng)
{
float pressure = pt->pressure;
float tmp_pressure = pt->pressure;
- if (brush->draw_jitter > 0.0f) {
- float curvef = curvemapping_evaluateF(brush->cur_jitter, 0, pressure);
- tmp_pressure = curvef * brush->draw_sensitivity;
+ if (brush->gpencil_settings->draw_jitter > 0.0f) {
+ float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_jitter, 0, pressure);
+ tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
}
- const float exfactor = (brush->draw_jitter + 2.0f) * (brush->draw_jitter + 2.0f); /* exponential value */
+ const float exfactor = (brush->gpencil_settings->draw_jitter + 2.0f) * (brush->gpencil_settings->draw_jitter + 2.0f); /* exponential value */
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 */
- if (gpd->sbuffer_size > 1) {
+ if (gpd->runtime.sbuffer_size > 1) {
mvec[0] = (float)(mval[0] - (pt - 1)->x);
mvec[1] = (float)(mval[1] - (pt - 1)->y);
normalize_v2(mvec);
@@ -451,18 +447,18 @@ static void gp_brush_jitter(
}
/* apply pressure change depending of the angle of the stroke to simulate a pen with shape */
-static void gp_brush_angle(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const int mval[2])
+static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const int mval[2])
{
float mvec[2];
- float sen = brush->draw_angle_factor; /* sensitivity */;
+ float sen = brush->gpencil_settings->draw_angle_factor; /* sensitivity */;
float fac;
float mpressure;
- float angle = brush->draw_angle; /* default angle of brush in radians */;
+ float angle = brush->gpencil_settings->draw_angle; /* default angle of brush in radians */;
float v0[2] = { cos(angle), sin(angle) }; /* angle vector of the brush with full thickness */
/* Apply to first point (only if there are 2 points because before no data to do it ) */
- if (gpd->sbuffer_size == 1) {
+ if (gpd->runtime.sbuffer_size == 1) {
mvec[0] = (float)(mval[0] - (pt - 1)->x);
mvec[1] = (float)(mval[1] - (pt - 1)->y);
normalize_v2(mvec);
@@ -475,7 +471,7 @@ static void gp_brush_angle(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const
}
/* apply from second point */
- if (gpd->sbuffer_size >= 1) {
+ if (gpd->runtime.sbuffer_size >= 1) {
mvec[0] = (float)(mval[0] - (pt - 1)->x);
mvec[1] = (float)(mval[1] - (pt - 1)->y);
normalize_v2(mvec);
@@ -490,21 +486,83 @@ static void gp_brush_angle(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const
}
+/* Apply smooth to buffer while drawing
+* to smooth point C, use 2 before (A, B) and current point (D):
+*
+* A----B-----C------D
+*
+* \param p Temp data
+* \param inf Influence factor
+* \param idx Index of the last point (need minimum 3 points in the array)
+*/
+static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
+{
+ bGPdata *gpd = p->gpd;
+ short num_points = gpd->runtime.sbuffer_size;
+
+ /* Do nothing if not enough points to smooth out */
+ if ((num_points < 3) || (idx < 3) || (inf == 0.0f)) {
+ return;
+ }
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ float steps = 4.0f;
+ if (idx < 4) {
+ steps--;
+ }
+
+ tGPspoint *pta = idx >= 4 ? &points[idx - 4] : NULL;
+ tGPspoint *ptb = idx >= 3 ? &points[idx - 3] : NULL;
+ tGPspoint *ptc = idx >= 2 ? &points[idx - 2] : NULL;
+ tGPspoint *ptd = &points[idx - 1];
+
+ float sco[2] = { 0.0f };
+ float a[2], b[2], c[2], d[2];
+ const float average_fac = 1.0f / steps;
+
+ /* Compute smoothed coordinate by taking the ones nearby */
+ if (pta) {
+ copy_v2fl_v2i(a, &pta->x);
+ madd_v2_v2fl(sco, a, average_fac);
+ }
+ if (ptb) {
+ copy_v2fl_v2i(b, &ptb->x);
+ madd_v2_v2fl(sco, b, average_fac);
+ }
+ if (ptc) {
+ copy_v2fl_v2i(c, &ptc->x);
+ madd_v2_v2fl(sco, c, average_fac);
+ }
+ if (ptd) {
+ copy_v2fl_v2i(d, &ptd->x);
+ madd_v2_v2fl(sco, d, average_fac);
+ }
+
+ /* Based on influence factor, blend between original and optimal smoothed coordinate */
+ interp_v2_v2v2(c, c, sco, inf);
+ round_v2i_v2fl(&ptc->x, c);
+}
+
/* add current stroke-point to buffer (returns whether point was successfully added) */
static short gp_stroke_addpoint(
tGPsdata *p, const int mval[2], float pressure, double curtime)
{
bGPdata *gpd = p->gpd;
- bGPDbrush *brush = p->brush;
+ Brush *brush = p->brush;
tGPspoint *pt;
ToolSettings *ts = p->scene->toolsettings;
+ Object *obact = (Object *)p->ownerPtr.data;
+ Depsgraph *depsgraph = p->depsgraph; \
+ RegionView3D *rv3d = p->ar->regiondata;
+ View3D *v3d = p->sa->spacedata.first;
+ MaterialGPencilStyle *gp_style = p->material->gp_style;
/* check painting mode */
if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
/* straight lines only - i.e. only store start and end point in buffer */
- if (gpd->sbuffer_size == 0) {
+ if (gpd->runtime.sbuffer_size == 0) {
/* first point in buffer (start point) */
- pt = (tGPspoint *)(gpd->sbuffer);
+ pt = (tGPspoint *)(gpd->runtime.sbuffer);
/* store settings */
copy_v2_v2_int(&pt->x, mval);
@@ -513,13 +571,13 @@ static short gp_stroke_addpoint(
pt->time = (float)(curtime - p->inittime);
/* increment buffer size */
- gpd->sbuffer_size++;
+ gpd->runtime.sbuffer_size++;
}
else {
/* just reset the endpoint to the latest value
* - assume that pointers for this are always valid...
*/
- pt = ((tGPspoint *)(gpd->sbuffer) + 1);
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
/* store settings */
copy_v2_v2_int(&pt->x, mval);
@@ -528,31 +586,35 @@ static short gp_stroke_addpoint(
pt->time = (float)(curtime - p->inittime);
/* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
- gpd->sbuffer_size = 2;
+ gpd->runtime.sbuffer_size = 2;
}
+ /* tag depsgraph to update object */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
/* can keep carrying on this way :) */
return GP_STROKEADD_NORMAL;
}
else if (p->paintmode == GP_PAINTMODE_DRAW) { /* normal drawing */
/* check if still room in buffer */
- if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX)
+ if (gpd->runtime.sbuffer_size >= GP_STROKE_BUFFER_MAX)
return GP_STROKEADD_OVERFLOW;
/* get pointer to destination point */
- pt = ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size);
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size);
/* store settings */
/* pressure */
- if (brush->flag & GP_BRUSH_USE_PRESSURE) {
- float curvef = curvemapping_evaluateF(brush->cur_sensitivity, 0, pressure);
- pt->pressure = curvef * brush->draw_sensitivity;
+ if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
+ float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_sensitivity, 0, pressure);
+ pt->pressure = curvef * brush->gpencil_settings->draw_sensitivity;
}
else {
pt->pressure = 1.0f;
}
+
/* Apply jitter to position */
- if (brush->draw_jitter > 0.0f) {
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && (brush->gpencil_settings->draw_jitter > 0.0f)) {
int r_mval[2];
gp_brush_jitter(gpd, brush, pt, mval, r_mval, p->rng);
copy_v2_v2_int(&pt->x, r_mval);
@@ -561,42 +623,62 @@ static short gp_stroke_addpoint(
copy_v2_v2_int(&pt->x, mval);
}
/* apply randomness to pressure */
- if ((brush->draw_random_press > 0.0f) && (brush->flag & GP_BRUSH_USE_RANDOM_PRESSURE)) {
- float curvef = curvemapping_evaluateF(brush->cur_sensitivity, 0, pressure);
- float tmp_pressure = curvef * brush->draw_sensitivity;
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_random_press > 0.0f))
+ {
+ float curvef = 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->draw_random_press * BLI_rng_get_float(p->rng);
+ pt->pressure -= tmp_pressure * brush->gpencil_settings->draw_random_press * BLI_rng_get_float(p->rng);
}
else {
- pt->pressure += tmp_pressure * brush->draw_random_press * BLI_rng_get_float(p->rng);
+ pt->pressure += tmp_pressure * brush->gpencil_settings->draw_random_press * BLI_rng_get_float(p->rng);
}
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;
+ }
+ else {
+ pt->uv_rot = (BLI_rng_get_float(p->rng) * M_PI) * brush->gpencil_settings->uv_random;
+ }
+ 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->draw_angle_factor > 0.0f) {
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_angle_factor > 0.0f))
+ {
gp_brush_angle(gpd, brush, pt, mval);
}
/* color strength */
- if (brush->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
- float curvef = curvemapping_evaluateF(brush->cur_strength, 0, pressure);
- float tmp_pressure = curvef * brush->draw_sensitivity;
+ if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
+ float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_strength, 0, pressure);
+ float tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
- pt->strength = tmp_pressure * brush->draw_strength;
+ pt->strength = tmp_pressure * brush->gpencil_settings->draw_strength;
}
else {
- pt->strength = brush->draw_strength;
+ pt->strength = brush->gpencil_settings->draw_strength;
}
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
/* apply randomness to color strength */
- if ((brush->draw_random_press > 0.0f) && (brush->flag & GP_BRUSH_USE_RANDOM_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->draw_random_press * BLI_rng_get_float(p->rng);
+ pt->strength -= pt->strength * brush->gpencil_settings->draw_random_strength * BLI_rng_get_float(p->rng);
}
else {
- pt->strength += pt->strength * brush->draw_random_press * BLI_rng_get_float(p->rng);
+ pt->strength += pt->strength * brush->gpencil_settings->draw_random_strength * BLI_rng_get_float(p->rng);
}
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
@@ -604,11 +686,49 @@ static short gp_stroke_addpoint(
/* point time */
pt->time = (float)(curtime - p->inittime);
+ /* point uv (only 3d view) */
+ if ((p->sa->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_size > 1)) {
+ float pixsize = gp_style->texture_pixsize / 1000000.0f;
+ tGPspoint *ptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 2;
+ bGPDspoint spt, spt2;
+
+ /* get origin to reproject point */
+ float origin[3];
+ gp_get_3d_reference(p, origin);
+ /* reproject current */
+ ED_gpencil_tpoint_to_point(p->ar, origin, pt, &spt);
+ ED_gp_project_point_to_plane(obact, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &spt);
+
+ /* reproject previous */
+ ED_gpencil_tpoint_to_point(p->ar, origin, ptb, &spt2);
+ ED_gp_project_point_to_plane(obact, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &spt2);
+
+ p->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize;
+ pt->uv_fac = p->totpixlen;
+ if ((gp_style) && (gp_style->sima)) {
+ pt->uv_fac /= gp_style->sima->gen_x;
+ }
+ }
+ else {
+ p->totpixlen = 0.0f;
+ pt->uv_fac = 0.0f;
+ }
+
/* increment counters */
- gpd->sbuffer_size++;
+ gpd->runtime.sbuffer_size++;
+
+ /* 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, brush->gpencil_settings->active_smooth * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_size - s);
+ }
+ }
+
+ /* tag depsgraph to update object */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
/* check if another operation can still occur */
- if (gpd->sbuffer_size == GP_STROKE_BUFFER_MAX)
+ if (gpd->runtime.sbuffer_size == GP_STROKE_BUFFER_MAX)
return GP_STROKEADD_FULL;
else
return GP_STROKEADD_NORMAL;
@@ -617,7 +737,7 @@ static short gp_stroke_addpoint(
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
/* get pointer to destination point */
- pt = (tGPspoint *)(gpd->sbuffer);
+ pt = (tGPspoint *)(gpd->runtime.sbuffer);
/* store settings */
copy_v2_v2_int(&pt->x, mval);
@@ -632,14 +752,17 @@ static short gp_stroke_addpoint(
if (gp_stroke_added_check(p)) {
bGPDstroke *gps = p->gpf->strokes.last;
bGPDspoint *pts;
+ MDeformVert *dvert;
/* first time point is adding to temporary buffer -- need to allocate new point in stroke */
- if (gpd->sbuffer_size == 0) {
+ if (gpd->runtime.sbuffer_size == 0) {
gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1));
gps->totpoints++;
}
pts = &gps->points[gps->totpoints - 1];
+ dvert = &gps->dvert[gps->totpoints - 1];
/* special case for poly lines: normally,
* depth is needed only when creating new stroke from buffer,
@@ -647,8 +770,6 @@ static short gp_stroke_addpoint(
* so initialize depth buffer before converting coordinates
*/
if (gpencil_project_check(p)) {
- View3D *v3d = p->sa->spacedata.first;
-
view3d_region_operator_needs_opengl(p->win, p->ar);
ED_view3d_autodist_init(
p->depsgraph, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
@@ -656,25 +777,32 @@ static short gp_stroke_addpoint(
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
- /* if axis locked, reproject to plane locked (only in 3d space) */
- if (p->lock_axis > GP_LOCKAXIS_NONE) {
- gp_reproject_toplane(p, gps);
- }
+ /* reproject to plane (only in 3d space) */
+ gp_reproject_toplane(p, gps);
/* if parented change position relative to parent object */
- if (gpl->parent != NULL) {
- gp_apply_parent_point(gpl, pts);
- }
+ 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;
+
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+
/* force fill recalc */
gps->flag |= GP_STROKE_RECALC_CACHES;
+ /* drawing batch cache is dirty now */
+ gp_update_cache(p->gpd);
}
/* increment counters */
- if (gpd->sbuffer_size == 0)
- gpd->sbuffer_size++;
+ if (gpd->runtime.sbuffer_size == 0)
+ gpd->runtime.sbuffer_size++;
+
+ /* tag depsgraph to update object */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
return GP_STROKEADD_NORMAL;
}
@@ -690,9 +818,9 @@ static short gp_stroke_addpoint(
static void gp_stroke_simplify(tGPsdata *p)
{
bGPdata *gpd = p->gpd;
- tGPspoint *old_points = (tGPspoint *)gpd->sbuffer;
- short num_points = gpd->sbuffer_size;
- short flag = gpd->sbuffer_sflag;
+ tGPspoint *old_points = (tGPspoint *)gpd->runtime.sbuffer;
+ short num_points = gpd->runtime.sbuffer_size;
+ short flag = gpd->runtime.sbuffer_sflag;
short i, j;
/* only simplify if simplification is enabled, and we're not doing a straight line */
@@ -707,9 +835,9 @@ static void gp_stroke_simplify(tGPsdata *p)
* - firstly set sbuffer to NULL, so a new one is allocated
* - secondly, reset flag after, as it gets cleared auto
*/
- gpd->sbuffer = NULL;
+ gpd->runtime.sbuffer = NULL;
gp_session_validatebuffer(p);
- gpd->sbuffer_sflag = flag;
+ gpd->runtime.sbuffer_sflag = flag;
/* macro used in loop to get position of new point
* - used due to the mixture of datatypes in use here
@@ -766,8 +894,11 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
bGPDstroke *gps;
bGPDspoint *pt;
tGPspoint *ptc;
- bGPDbrush *brush = p->brush;
+ MDeformVert *dvert;
+ Brush *brush = p->brush;
ToolSettings *ts = p->scene->toolsettings;
+ Depsgraph *depsgraph = p->depsgraph;
+ Object *obact = (Object *)p->ownerPtr.data;
int i, totelem;
/* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
@@ -777,14 +908,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
* - drawing straight-lines only requires the endpoints
*/
if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT)
- totelem = (gpd->sbuffer_size >= 2) ? 2 : gpd->sbuffer_size;
+ totelem = (gpd->runtime.sbuffer_size >= 2) ? 2 : gpd->runtime.sbuffer_size;
else
- totelem = gpd->sbuffer_size;
+ totelem = gpd->runtime.sbuffer_size;
/* exit with error if no valid points from this stroke */
if (totelem == 0) {
if (G.debug & G_DEBUG)
- printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", gpd->sbuffer_size);
+ printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", gpd->runtime.sbuffer_size);
return;
}
@@ -793,6 +924,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
* 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;
}
@@ -803,95 +937,94 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* copy appropriate settings for stroke */
gps->totpoints = totelem;
- gps->thickness = brush->thickness;
- gps->flag = gpd->sbuffer_sflag;
+ gps->thickness = brush->size;
+ 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_CACHES;
/* allocate enough memory for a continuous array for storage points */
- int sublevel = brush->sublevel;
- int new_totpoints = gps->totpoints;
+ const int subdivide = brush->gpencil_settings->draw_subdivide;
+
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights");
- for (i = 0; i < sublevel; i++) {
- new_totpoints += new_totpoints - 1;
- }
- gps->points = MEM_callocN(sizeof(bGPDspoint) * new_totpoints, "gp_stroke_points");
/* initialize triangle memory to dummy data */
gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation");
gps->flag |= GP_STROKE_RECALC_CACHES;
gps->tot_triangles = 0;
+ /* drawing batch cache is dirty now */
+ gp_update_cache(p->gpd);
/* set pointer to first non-initialized point */
pt = gps->points + (gps->totpoints - totelem);
+ dvert = gps->dvert + (gps->totpoints - totelem);
/* copy points from the buffer to the stroke */
if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
/* straight lines only -> only endpoints */
{
/* first point */
- ptc = gpd->sbuffer;
+ ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
- /* if axis locked, reproject to plane locked (only in 3d space) */
- if (p->lock_axis > GP_LOCKAXIS_NONE) {
- gp_reproject_toplane(p, gps);
- }
- /* if parented change position relative to parent object */
- if (gpl->parent != NULL) {
- gp_apply_parent_point(gpl, pt);
- }
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+
pt++;
+ dvert++;
}
if (totelem == 2) {
/* last point if applicable */
- ptc = ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1);
+ ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_size - 1);
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
- /* if axis locked, reproject to plane locked (only in 3d space) */
- if (p->lock_axis > GP_LOCKAXIS_NONE) {
- gp_reproject_toplane(p, gps);
- }
- /* if parented change position relative to parent object */
- if (gpl->parent != NULL) {
- gp_apply_parent_point(gpl, pt);
- }
-
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
+
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ }
+
+ /* reproject to plane (only in 3d space) */
+ gp_reproject_toplane(p, gps);
+ 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);
}
}
else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
/* first point */
- ptc = gpd->sbuffer;
+ ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
- /* if axis locked, reproject to plane locked (only in 3d space) */
- if (p->lock_axis > GP_LOCKAXIS_NONE) {
- gp_reproject_toplane(p, gps);
- }
+ /* reproject to plane (only in 3d space) */
+ gp_reproject_toplane(p, gps);
/* if parented change position relative to parent object */
- if (gpl->parent != NULL) {
- gp_apply_parent_point(gpl, pt);
- }
+ gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
+
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+
}
else {
float *depth_arr = NULL;
@@ -902,9 +1035,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
int interp_depth = 0;
int found_depth = 0;
- depth_arr = MEM_mallocN(sizeof(float) * gpd->sbuffer_size, "depth_points");
+ depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_size, "depth_points");
- for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size; i++, ptc++, pt++) {
+ for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size; i++, ptc++, pt++) {
copy_v2_v2_int(mval, &ptc->x);
if ((ED_view3d_autodist_depth(p->ar, mval, depth_margin, depth_arr + i) == 0) &&
@@ -921,7 +1054,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
if (found_depth == false) {
/* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
- for (i = gpd->sbuffer_size - 1; i >= 0; i--)
+ for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--)
depth_arr[i] = 0.9999f;
}
else {
@@ -930,13 +1063,13 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
int first_valid = 0;
int last_valid = 0;
- for (i = 0; i < gpd->sbuffer_size; i++) {
+ for (i = 0; i < gpd->runtime.sbuffer_size; i++) {
if (depth_arr[i] != FLT_MAX)
break;
}
first_valid = i;
- for (i = gpd->sbuffer_size - 1; i >= 0; i--) {
+ for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--) {
if (depth_arr[i] != FLT_MAX)
break;
}
@@ -950,16 +1083,15 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
}
if (interp_depth) {
- interp_sparse_array(depth_arr, gpd->sbuffer_size, FLT_MAX);
+ interp_sparse_array(depth_arr, gpd->runtime.sbuffer_size, FLT_MAX);
}
}
}
-
pt = gps->points;
/* convert all points (normal behavior) */
- for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++, pt++) {
+ for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size && ptc; i++, ptc++, pt++) {
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
@@ -968,20 +1100,18 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
+ pt->uv_fac = ptc->uv_fac;
+ pt->uv_rot = ptc->uv_rot;
}
- /* subdivide the stroke */
- if (sublevel > 0) {
- int totpoints = gps->totpoints;
- for (i = 0; i < sublevel; i++) {
- /* we're adding one new point between each pair of verts on each step */
- totpoints += totpoints - 1;
-
- gp_subdivide_stroke(gps, totpoints);
- }
+ /* subdivide and smooth the stroke */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) && (subdivide > 0)) {
+ gp_subdivide_stroke(gps, subdivide);
}
/* apply randomness to stroke */
- if (brush->draw_random_sub > 0.0f) {
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_random_sub > 0.0f))
+ {
gp_randomize_stroke(gps, brush, p->rng);
}
@@ -989,34 +1119,43 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
* for each iteration, the factor is reduced to get a better smoothing without changing too much
* the original stroke
*/
- if (brush->draw_smoothfac > 0.0f) {
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
+ (brush->gpencil_settings->draw_smoothfac > 0.0f))
+ {
float reduce = 0.0f;
- for (int r = 0; r < brush->draw_smoothlvl; ++r) {
+ for (int r = 0; r < brush->gpencil_settings->draw_smoothlvl; r++) {
for (i = 0; i < gps->totpoints; i++) {
- /* NOTE: No pressure smoothing, or else we get annoying thickness changes while drawing... */
- gp_smooth_stroke(gps, i, brush->draw_smoothfac - reduce, false);
+ BKE_gpencil_smooth_stroke(gps, i, brush->gpencil_settings->draw_smoothfac - reduce);
+ BKE_gpencil_smooth_stroke_strength(gps, i, brush->gpencil_settings->draw_smoothfac);
}
reduce += 0.25f; // reduce the factor
}
}
-
- /* if axis locked, reproject to plane locked (only in 3d space) */
- if (p->lock_axis > GP_LOCKAXIS_NONE) {
- gp_reproject_toplane(p, gps);
- }
- /* if parented change position relative to parent object */
- if (gpl->parent != NULL) {
- gp_apply_parent(gpl, gps);
+ /* 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; i++) {
+ BKE_gpencil_smooth_stroke_thickness(gps, i, brush->gpencil_settings->thick_smoothfac);
+ }
+ }
}
+ /* 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);
+
if (depth_arr)
MEM_freeN(depth_arr);
}
- /* Save palette color */
- bGPDpalette *palette = BKE_gpencil_palette_getactive(p->gpd);
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
- gps->palcolor = palcolor;
- BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname));
+
+ /* Save material index */
+ gps->mat_nr = BKE_object_material_slot_find_index(p->ob, p->material) - 1;
+
+ /* 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
@@ -1047,6 +1186,8 @@ static float view3d_point_depth(const RegionView3D *rv3d, const float co[3])
/* only erase stroke points that are visible */
static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y)
{
+ Object *obact = (Object *)p->ownerPtr.data;
+
if ((p->sa->spacetype == SPACE_VIEW3D) &&
(p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH))
{
@@ -1059,7 +1200,7 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, cons
float diff_mat[4][4];
/* calculate difference matrix if parent object */
- ED_gpencil_parent_location(gpl, diff_mat);
+ ED_gpencil_parent_location(p->depsgraph, obact, p->gpd, gpl, diff_mat);
if (ED_view3d_autodist_simple(p->ar, mval, mval_3d, 0, NULL)) {
const float depth_mval = view3d_point_depth(rv3d, mval_3d);
@@ -1092,6 +1233,24 @@ static float gp_stroke_eraser_calc_influence(tGPsdata *p, const int mval[2], con
return fac;
}
+/* helper to free a stroke */
+static void gp_free_stroke(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps)
+{
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+ gp_update_cache(gpd);
+}
+
/* eraser tool - evaluation per stroke */
/* TODO: this could really do with some optimization (KD-Tree/BVH?) */
static void gp_stroke_eraser_dostroke(tGPsdata *p,
@@ -1099,46 +1258,58 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
const int mval[2], const int mvalo[2],
const int radius, const rcti *rect)
{
+ Depsgraph *depsgraph = p->depsgraph;
+ Object *obact = (Object *)p->ownerPtr.data;
+ Brush *eraser = p->eraser;
bGPDspoint *pt1, *pt2;
int pc1[2] = {0};
int pc2[2] = {0};
int i;
float diff_mat[4][4];
- /* calculate difference matrix if parent object */
- if (gpl->parent != NULL) {
- ED_gpencil_parent_location(gpl, diff_mat);
- }
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, p->gpd, gpl, diff_mat);
if (gps->totpoints == 0) {
/* just free stroke */
- if (gps->points)
- MEM_freeN(gps->points);
- if (gps->triangles)
- MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ gp_free_stroke(p->gpd, gpf, gps);
}
else if (gps->totpoints == 1) {
/* only process if it hasn't been masked out... */
if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
- if (gpl->parent == NULL) {
- gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
- }
- else {
- bGPDspoint pt_temp;
- gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
- gp_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+ bGPDspoint pt_temp;
+ gp_point_to_parent_space(gps->points, 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])) {
+ /* only check if point is inside */
+ if (len_v2v2_int(mval, pc1) <= radius) {
+ /* free stroke */
+ gp_free_stroke(p->gpd, gpf, gps);
+ }
}
+ }
+ }
+ else if ((p->flags & GP_PAINTFLAG_STROKE_ERASER) || (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_STROKE)) {
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+
+ /* only process if it hasn't been masked out... */
+ if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
+ continue;
+
+ /* get points to work with */
+ pt1 = gps->points + i;
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(&p->gsc, gps, &npt, &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])) {
/* only check if point is inside */
if (len_v2v2_int(mval, pc1) <= radius) {
/* free stroke */
- // XXX: pressure sensitive eraser should apply here too?
- MEM_freeN(gps->points);
- if (gps->triangles)
- MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ gp_free_stroke(p->gpd, gpf, gps);
+ return;
}
}
}
@@ -1181,18 +1352,12 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
continue;
- if (gpl->parent == NULL) {
- gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
- gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
- }
- else {
- bGPDspoint npt;
- gp_point_to_parent_space(pt1, diff_mat, &npt);
- gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, 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_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
- }
+ gp_point_to_parent_space(pt2, 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 */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
@@ -1215,11 +1380,15 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
pt2->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc2) * strength / 2.0f;
/* 2) Tag any point with overly low influence for removal in the next pass */
- if (pt1->pressure < cull_thresh) {
+ if ((pt1->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) ||
+ (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD))
+ {
pt1->flag |= GP_SPOINT_TAG;
do_cull = true;
}
- if (pt2->pressure < cull_thresh) {
+ if ((pt2->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) ||
+ (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD))
+ {
pt2->flag |= GP_SPOINT_TAG;
do_cull = true;
}
@@ -1230,8 +1399,9 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* Second Pass: Remove any points that are tagged */
if (do_cull) {
- gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG);
+ gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false);
}
+ gp_update_cache(p->gpd);
}
}
@@ -1275,7 +1445,7 @@ static void gp_stroke_doeraser(tGPsdata *p)
for (gps = gpf->strokes.first; gps; gps = gpn) {
gpn = gps->next;
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ if (ED_gpencil_stroke_color_use(p->ob, gpl, gps) == false) {
continue;
}
/* Not all strokes in the datablock may be valid in the current editor/context
@@ -1295,107 +1465,178 @@ static void gp_stroke_doeraser(tGPsdata *p)
static void gp_session_validatebuffer(tGPsdata *p)
{
bGPdata *gpd = p->gpd;
+ Brush *brush = p->brush;
/* clear memory of buffer (or allocate it if starting a new session) */
- if (gpd->sbuffer) {
+ if (gpd->runtime.sbuffer) {
/* printf("\t\tGP - reset sbuffer\n"); */
- memset(gpd->sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
+ memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
}
else {
/* printf("\t\tGP - allocate sbuffer\n"); */
- gpd->sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
+ gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
}
/* reset indices */
- gpd->sbuffer_size = 0;
+ gpd->runtime.sbuffer_size = 0;
/* reset flags */
- gpd->sbuffer_sflag = 0;
+ gpd->runtime.sbuffer_sflag = 0;
/* reset inittime */
p->inittime = 0.0;
+
+ /* reset lazy */
+ if (brush) {
+ brush->gpencil_settings->flag &= ~GP_BRUSH_STABILIZE_MOUSE_TEMP;
+ }
}
-/* create a new palette color */
-static bGPDpalettecolor *gp_create_new_color(bGPDpalette *palette)
+/* helper to get default eraser and create one if no eraser brush */
+static Brush *gp_get_default_eraser(Main *bmain, ToolSettings *ts)
{
- bGPDpalettecolor *palcolor;
+ Brush *brush_dft = NULL;
+ Paint *paint = BKE_brush_get_gpencil_paint(ts);
+ Brush *brush_old = paint->brush;
+ for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+ if ((brush->ob_mode == OB_MODE_GPENCIL_PAINT) &&
+ (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE))
+ {
+ /* save first eraser to use later if no default */
+ if (brush_dft == NULL) {
+ brush_dft = brush;
+ }
+ /* found default */
+ if(brush->gpencil_settings->flag & GP_BRUSH_DEFAULT_ERASER) {
+ return brush;
+ }
+ }
+ }
+ /* if no default, but exist eraser brush, return this and set as default */
+ if (brush_dft) {
+ brush_dft->gpencil_settings->flag |= GP_BRUSH_DEFAULT_ERASER;
+ return brush_dft;
+ }
+ /* create a new soft eraser brush */
+ else {
+ brush_dft = BKE_brush_add_gpencil(bmain, ts, "Soft Eraser");
+ brush_dft->size = 30.0f;
+ brush_dft->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
+ brush_dft->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
+ brush_dft->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
+ brush_dft->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
- palcolor = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
+ /* reset current brush */
+ BKE_paint_brush_set(paint, brush_old);
- return palcolor;
+ return brush_dft;
+ }
}
/* initialize a drawing brush */
-static void gp_init_drawing_brush(ToolSettings *ts, tGPsdata *p)
+static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
{
- bGPDbrush *brush;
+ Brush *brush;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ Paint *paint = BKE_brush_get_gpencil_paint(ts);
/* if not exist, create a new one */
- if (BLI_listbase_is_empty(&ts->gp_brushes)) {
+ if (paint->brush == NULL) {
/* create new brushes */
- BKE_gpencil_brush_init_presets(ts);
- brush = BKE_gpencil_brush_getactive(ts);
+ BKE_brush_gpencil_presets(C);
+ brush = BKE_brush_getactive_gpencil(ts);
}
else {
/* Use the current */
- brush = BKE_gpencil_brush_getactive(ts);
+ brush = BKE_brush_getactive_gpencil(ts);
}
/* be sure curves are initializated */
- curvemapping_initialize(brush->cur_sensitivity);
- curvemapping_initialize(brush->cur_strength);
- curvemapping_initialize(brush->cur_jitter);
+ curvemapping_initialize(brush->gpencil_settings->curve_sensitivity);
+ curvemapping_initialize(brush->gpencil_settings->curve_strength);
+ curvemapping_initialize(brush->gpencil_settings->curve_jitter);
/* asign to temp tGPsdata */
p->brush = brush;
+ if (brush->gpencil_settings->brush_type != GP_BRUSH_TYPE_ERASE) {
+ p->eraser = gp_get_default_eraser(p->bmain, ts);
+ }
+ else {
+ p->eraser = brush;
+ }
+ /* 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.
+ *
+ */
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
}
-/* initialize a paint palette brush and a default color if not exist */
-static void gp_init_palette(tGPsdata *p)
+/* initialize a paint brush and a default color if not exist */
+static void gp_init_colors(tGPsdata *p)
{
- bGPdata *gpd;
- bGPDpalette *palette;
- bGPDpalettecolor *palcolor;
+ bGPdata *gpd = p->gpd;
+ Brush *brush = p->brush;
- gpd = p->gpd;
+ Material *ma = NULL;
+ MaterialGPencilStyle *gp_style = NULL;
+
+ /* use brush material */
+ ma = BKE_gpencil_get_material_from_brush(brush);
+
+ /* if no brush defaults, get material and color info
+ * NOTE: Ensures that everything we need will exist...
+ */
+ if ((ma == NULL) || (ma->gp_style == NULL)) {
+ BKE_gpencil_material_ensure(p->bmain, p->ob);
- /* if not exist, create a new palette */
- if (BLI_listbase_is_empty(&gpd->palettes)) {
- /* create new palette */
- palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true);
- /* now create a default color */
- palcolor = gp_create_new_color(palette);
+ /* assign always the first material to the brush */
+ p->material = give_current_material(p->ob, 1);
+ brush->gpencil_settings->material = p->material;
}
else {
- /* Use the current palette and color */
- palette = BKE_gpencil_palette_getactive(gpd);
- /* the palette needs one color */
- if (BLI_listbase_is_empty(&palette->colors)) {
- palcolor = gp_create_new_color(palette);
- }
- else {
- palcolor = BKE_gpencil_palettecolor_getactive(palette);
- }
- /* in some situations can be null, so use first */
- if (palcolor == NULL) {
- BKE_gpencil_palettecolor_setactive(palette, palette->colors.first);
- palcolor = palette->colors.first;
- }
+ p->material = ma;
}
- /* asign to temp tGPsdata */
- p->palettecolor = palcolor;
+ /* check if the material is already on object material slots and add it if missing */
+ if (BKE_object_material_slot_find_index(p->ob, p->material) == 0) {
+ BKE_object_material_slot_add(p->bmain, p->ob);
+ assign_material(p->bmain, p->ob, ma, p->ob->totcol, BKE_MAT_ASSIGN_EXISTING);
+ }
+
+ /* assign color information to temp tGPsdata */
+ gp_style = p->material->gp_style;
+ if (gp_style) {
+
+ /* set colors */
+ copy_v4_v4(gpd->runtime.scolor, gp_style->stroke_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;
+ }
}
/* (re)init new painting data */
-static bool gp_session_initdata(bContext *C, tGPsdata *p)
+static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p)
{
Main *bmain = CTX_data_main(C);
bGPdata **gpd_ptr = NULL;
ScrArea *curarea = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *obact = CTX_data_active_object(C);
+ View3D *v3d = curarea->spacedata.first;
/* make sure the active view (at the starting time) is a 3d-view */
if (curarea == NULL) {
@@ -1406,10 +1647,12 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
}
/* pass on current scene and window */
+ p->C = C;
p->bmain = CTX_data_main(C);
p->scene = CTX_data_scene(C);
p->depsgraph = CTX_data_depsgraph(C);
p->win = CTX_wm_window(C);
+ p->disable_fill = RNA_boolean_get(op->ptr, "disable_fill");
unit_m4(p->imat);
unit_m4(p->mat);
@@ -1424,7 +1667,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* set current area
* - must verify that region data is 3D-view (and not something else)
*/
- /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
+ /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
p->sa = curarea;
p->ar = ar;
p->align_flag = &ts->gpencil_v3d_align;
@@ -1435,92 +1678,19 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
printf("Error: 3D-View active region doesn't have any region data, so cannot be drawable\n");
return 0;
}
- break;
- }
- case SPACE_NODE:
- {
- /* SpaceNode *snode = curarea->spacedata.first; */
- /* set current area */
- p->sa = curarea;
- p->ar = ar;
- p->v2d = &ar->v2d;
- p->align_flag = &ts->gpencil_v2d_align;
- break;
- }
- case SPACE_SEQ:
- {
- SpaceSeq *sseq = curarea->spacedata.first;
-
- /* set current area */
- p->sa = curarea;
- p->ar = ar;
- p->v2d = &ar->v2d;
- p->align_flag = &ts->gpencil_seq_align;
-
- /* check that gpencil data is allowed to be drawn */
- if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil\n");
- return 0;
+ /* if active object doesn't exist or isn't a GP Object, create one */
+ float *cur = ED_view3d_cursor3d_get(p->scene, v3d)->location;
+ if ((!obact) || (obact->type != OB_GPENCIL)) {
+ /* create new default object */
+ obact = ED_add_gpencil_object(C, p->scene, cur);
}
- break;
- }
- case SPACE_IMAGE:
- {
- /* SpaceImage *sima = curarea->spacedata.first; */
+ /* assign object after all checks to be sure we have one active */
+ p->ob = obact;
- /* set the current area */
- p->sa = curarea;
- p->ar = ar;
- p->v2d = &ar->v2d;
- p->align_flag = &ts->gpencil_ima_align;
- break;
- }
- case SPACE_CLIP:
- {
- SpaceClip *sc = curarea->spacedata.first;
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (clip == NULL) {
- p->status = GP_STATUS_ERROR;
- return false;
- }
-
- /* set the current area */
- p->sa = curarea;
- p->ar = ar;
- p->v2d = &ar->v2d;
- p->align_flag = &ts->gpencil_v2d_align;
-
- invert_m4_m4(p->imat, sc->unistabmat);
-
- /* custom color for new layer */
- p->custom_color[0] = 1.0f;
- p->custom_color[1] = 0.0f;
- p->custom_color[2] = 0.5f;
- p->custom_color[3] = 0.9f;
-
- if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
- int framenr = ED_space_clip_get_clip_frame_number(sc);
- MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
- MovieTrackingMarker *marker = track ? BKE_tracking_marker_get(track, framenr) : NULL;
-
- if (marker) {
- p->imat[3][0] -= marker->pos[0];
- p->imat[3][1] -= marker->pos[1];
- }
- else {
- p->status = GP_STATUS_ERROR;
- return false;
- }
- }
-
- invert_m4_m4(p->mat, p->imat);
- copy_m4_m4(p->gsc.mat, p->mat);
break;
}
+
/* unsupported views */
default:
{
@@ -1533,7 +1703,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* get gp-data */
gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr);
- if (gpd_ptr == NULL) {
+ if ((gpd_ptr == NULL) || ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) {
p->status = GP_STATUS_ERROR;
if (G.debug & G_DEBUG)
printf("Error: Current context doesn't allow for any Grease Pencil data\n");
@@ -1555,16 +1725,18 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* clear out buffer (stored in gp-data), in case something contaminated it */
gp_session_validatebuffer(p);
+
/* set brush and create a new one if null */
- gp_init_drawing_brush(ts, p);
- /* set palette info and create a new one if null */
- gp_init_palette(p);
- /* set palette colors */
- bGPDpalettecolor *palcolor = p->palettecolor;
- bGPdata *pdata = p->gpd;
- copy_v4_v4(pdata->scolor, palcolor->color);
- copy_v4_v4(pdata->sfill, palcolor->fill);
- pdata->sflag = palcolor->flag;
+ gp_init_drawing_brush(C, p);
+
+ /* setup active color */
+ if (curarea->spacetype == SPACE_VIEW3D) {
+ /* NOTE: This is only done for 3D view, as Materials aren't used for
+ * annotations in 2D editors
+ */
+ gp_init_colors(p);
+ }
+
/* lock axis */
p->lock_axis = ts->gp_sculpt.lock_axis;
@@ -1572,20 +1744,22 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
}
/* init new painting session */
-static tGPsdata *gp_session_initpaint(bContext *C)
+static tGPsdata *gp_session_initpaint(bContext *C, wmOperator *op)
{
tGPsdata *p = NULL;
/* create new context data */
p = MEM_callocN(sizeof(tGPsdata), "GPencil Drawing Data");
- gp_session_initdata(C, p);
+ gp_session_initdata(C, op, p);
+#if 0
/* radius for eraser circle is defined in userprefs now */
/* NOTE: we do this here, so that if we exit immediately,
* erase size won't get lost
*/
p->radius = U.gp_eraser;
+#endif
/* Random generator, only init once. */
uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
@@ -1606,15 +1780,15 @@ static void gp_session_cleanup(tGPsdata *p)
return;
/* free stroke buffer */
- if (gpd->sbuffer) {
+ if (gpd->runtime.sbuffer) {
/* printf("\t\tGP - free sbuffer\n"); */
- MEM_freeN(gpd->sbuffer);
- gpd->sbuffer = NULL;
+ MEM_freeN(gpd->runtime.sbuffer);
+ gpd->runtime.sbuffer = NULL;
}
/* clear flags */
- gpd->sbuffer_size = 0;
- gpd->sbuffer_sflag = 0;
+ gpd->runtime.sbuffer_size = 0;
+ gpd->runtime.sbuffer_sflag = 0;
p->inittime = 0.0;
}
@@ -1632,11 +1806,12 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
{
Scene *scene = p->scene;
ToolSettings *ts = scene->toolsettings;
+ int cfra_eval = (int)DEG_get_ctime(p->depsgraph);
/* get active layer (or add a new one if non-existent) */
p->gpl = BKE_gpencil_layer_getactive(p->gpd);
if (p->gpl == NULL) {
- p->gpl = BKE_gpencil_layer_addnew(p->gpd, "GP_Layer", true);
+ p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("GP_Layer"), true);
if (p->custom_color[3])
copy_v3_v3(p->gpl->color, p->custom_color);
@@ -1670,7 +1845,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
* -> 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);
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_COPY);
has_layer_to_erase = true;
}
@@ -1708,7 +1883,9 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
else
add_frame_mode = GP_GETFRAME_ADD_NEW;
- p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
+ p->gpf = BKE_gpencil_layer_getframe(p->gpl, cfra_eval, add_frame_mode);
+ /* set as dirty draw manager cache */
+ gp_update_cache(p->gpd);
if (p->gpf == NULL) {
p->status = GP_STATUS_ERROR;
@@ -1724,7 +1901,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* set 'eraser' for this stroke if using eraser */
p->paintmode = paintmode;
if (p->paintmode == GP_PAINTMODE_ERASER) {
- p->gpd->sbuffer_sflag |= GP_STROKE_ERASER;
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_ERASER;
/* check if we should respect depth while erasing */
if (p->sa->spacetype == SPACE_VIEW3D) {
@@ -1735,7 +1912,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
}
else {
/* disable eraser flags - so that we can switch modes during a session */
- p->gpd->sbuffer_sflag &= ~GP_STROKE_ERASER;
+ p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_ERASER;
if (p->sa->spacetype == SPACE_VIEW3D) {
if (p->gpl->flag & GP_LAYER_NO_XRAY) {
@@ -1744,10 +1921,16 @@ 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 */
p->flags |= GP_PAINTFLAG_FIRSTRUN;
-
/* when drawing in the camera view, in 2D space, set the subrect */
p->subrect = NULL;
if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
@@ -1782,41 +1965,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
switch (p->sa->spacetype) {
case SPACE_VIEW3D:
{
- p->gpd->sbuffer_sflag |= GP_STROKE_3DSPACE;
- break;
- }
- case SPACE_NODE:
- {
- p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
- break;
- }
- case SPACE_SEQ:
- {
- p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
- break;
- }
- case SPACE_IMAGE:
- {
- SpaceImage *sima = (SpaceImage *)p->sa->spacedata.first;
-
- /* only set these flags if the image editor doesn't have an image active,
- * otherwise user will be confused by strokes not appearing after they're drawn
- *
- * Admittedly, this is a bit hacky, but it works much nicer from an ergonomic standpoint!
- */
- if (ELEM(NULL, sima, sima->image)) {
- /* make strokes be drawn in screen space */
- p->gpd->sbuffer_sflag &= ~GP_STROKE_2DSPACE;
- *(p->align_flag) &= ~GP_PROJECT_VIEWSPACE;
- }
- else {
- p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
- }
- break;
- }
- case SPACE_CLIP:
- {
- p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
break;
}
}
@@ -1839,7 +1988,7 @@ static void gp_paint_strokeend(tGPsdata *p)
}
/* check if doing eraser or not */
- if ((p->gpd->sbuffer_sflag & GP_STROKE_ERASER) == 0) {
+ if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
/* simplify stroke before transferring? */
gp_stroke_simplify(p);
@@ -1920,10 +2069,12 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en
p->erasercursor = NULL;
}
else if (enable && !p->erasercursor) {
+ ED_gpencil_toggle_brush_cursor(p->C, false, NULL);
/* enable cursor */
- p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- NULL, /* XXX */
- gpencil_draw_eraser, p);
+ p->erasercursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ NULL, /* XXX */
+ gpencil_draw_eraser, p);
}
}
@@ -1943,13 +2094,26 @@ static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
static void gpencil_draw_exit(bContext *C, wmOperator *op)
{
tGPsdata *p = op->customdata;
+ bGPdata *gpd = CTX_data_gpencil_data(C);
/* clear undo stack */
gpencil_undo_finish();
/* restore cursor to indicate end of drawing */
- WM_cursor_modal_restore(CTX_wm_window(C));
+ if (p->sa->spacetype != SPACE_VIEW3D) {
+ WM_cursor_modal_restore(CTX_wm_window(C));
+ }
+ else {
+ /* or restore paint if 3D view */
+ if ((p) && (p->paintmode == GP_PAINTMODE_ERASER)) {
+ WM_cursor_modal_set(p->win, CURSOR_STD);
+ }
+ /* drawing batch cache is dirty now */
+ if (gpd) {
+ gp_update_cache(gpd);
+ }
+ }
/* don't assume that operator data exists at all */
if (p) {
/* check size of buffer before cleanup, to determine if anything happened here */
@@ -1962,11 +2126,16 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
* NOTE: Do this even when not in eraser mode, as eraser may
* have been toggled at some point.
*/
- U.gp_eraser = p->radius;
+ if (p->eraser) {
+ p->eraser->size = p->radius;
+ }
/* cleanup */
gp_paint_cleanup(p);
gp_session_cleanup(p);
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+
+ /* finally, free the temp data */
gp_session_free(p);
}
@@ -1986,9 +2155,18 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p;
eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Brush *brush = BKE_brush_getactive_gpencil(ts);
+
+ /* if mode is draw and the brush is eraser, cancel */
+ if (paintmode != GP_PAINTMODE_ERASER) {
+ if ((brush) && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) {
+ return 0;
+ }
+ }
/* check context */
- p = op->customdata = gp_session_initpaint(C);
+ p = op->customdata = gp_session_initpaint(C, op);
if ((p == NULL) || (p->status == GP_STATUS_ERROR)) {
/* something wasn't set correctly in context */
gpencil_draw_exit(C, op);
@@ -2009,6 +2187,8 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
p->keymodifier = -1;
}
+ p->reports = op->reports;
+
/* everything is now setup ok */
return 1;
}
@@ -2019,10 +2199,15 @@ 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)
{
- if (p->paintmode == GP_PAINTMODE_ERASER)
+ Brush *brush = p->brush;
+ if ((p->paintmode == GP_PAINTMODE_ERASER) ||
+ (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE))
+ {
WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
- else
- WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
+ }
+ else {
+ WM_cursor_modal_set(p->win, CURSOR_STD);
+ }
}
/* update UI indicators of status, including cursor and header prints */
@@ -2030,11 +2215,21 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
{
/* header prints */
switch (p->status) {
- case GP_STATUS_PAINTING:
- /* only print this for paint-sessions, otherwise it gets annoying */
- if (GPENCIL_SKETCH_SESSIONS_ON(p->scene))
- ED_workspace_status_text(C, IFACE_("Grease Pencil: Drawing/erasing stroke... Release to end stroke"));
- break;
+
+#if 0 /* FIXME, this never runs! */
+ switch (p->paintmode) {
+ case GP_PAINTMODE_DRAW_POLY:
+ /* Provide usage tips, since this is modal, and unintuitive without hints */
+ ED_workspace_status_text(C, IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+ default:
+ /* Do nothing - the others are self explanatory, exit quickly once the mouse is released
+ * Showing any text would just be annoying as it would flicker.
+ */
+ break;
+ }
+#endif
case GP_STATUS_IDLING:
/* print status info */
@@ -2048,12 +2243,11 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
"ESC/Enter to end (or click outside this area)"));
break;
case GP_PAINTMODE_DRAW:
- ED_workspace_status_text(C, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw | "
- "E/ESC/Enter to end (or click outside this area)"));
+ ED_workspace_status_text(C, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw"));
break;
case GP_PAINTMODE_DRAW_POLY:
ED_workspace_status_text(C, IFACE_("Grease Pencil Poly Session: LMB click to place next stroke vertex | "
- "ESC/Enter to end (or click outside this area)"));
+ "Release Shift/ESC/Enter to end (or click outside this area)"));
break;
default: /* unhandled future cases */
@@ -2067,14 +2261,19 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
/* clear status string */
ED_workspace_status_text(C, NULL);
break;
+ case GP_STATUS_PAINTING:
+ break;
}
}
/* ------------------------------- */
/* create a new stroke point at the point indicated by the painting context */
-static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph)
+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 */
@@ -2087,6 +2286,17 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph
}
/* 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_v2fl_v2i(now_mouse, p->mval);
+ copy_v2fl_v2i(last_mouse, p->mvalo);
+ interp_v2_v2v2(now_mouse, now_mouse, last_mouse, p->brush->smooth_stroke_factor);
+ round_v2i_v2fl(p->mval, now_mouse);
+ }
+
/* try to add point */
short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
@@ -2124,11 +2334,24 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph
p->mvalo[1] = p->mval[1];
p->opressure = p->pressure;
p->ocurtime = p->curtime;
+
+ pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 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_size > 0))
+ {
+ pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 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(wmOperator *op, const wmEvent *event, Depsgraph *depsgraph)
+static void gpencil_draw_apply_event(bContext *C, wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, int x, int y)
{
tGPsdata *p = op->customdata;
PointerRNA itemptr;
@@ -2136,13 +2359,15 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsg
int tablet = 0;
/* convert from window-space to area-space mouse coordinates
+ * add any x,y override position for fake events
* NOTE: float to ints conversions, +1 factor is probably used to ensure a bit more accurate rounding...
*/
- p->mval[0] = event->mval[0] + 1;
- p->mval[1] = event->mval[1] + 1;
+ p->mval[0] = event->mval[0] + 1 - x;
+ p->mval[1] = event->mval[1] + 1 - y;
+ p->shift = event->shift;
/* verify key status for straight lines */
- if ((event->ctrl > 0) || (event->alt > 0)) {
+ if ((event->alt > 0) && (RNA_boolean_get(op->ptr, "disable_straight") == false)) {
if (p->straight[0] == 0) {
int dx = abs(p->mval[0] - p->mvalo[0]);
int dy = abs(p->mval[1] - p->mvalo[1]);
@@ -2151,12 +2376,12 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsg
if (dx >= dy) {
/* horizontal */
p->straight[0] = 1;
- p->straight[1] = p->mval[1]; /* save y */
+ p->straight[1] = (short)p->mval[1]; /* save y */
}
else {
/* vertical */
p->straight[0] = 2;
- p->straight[1] = p->mval[0]; /* save x */
+ p->straight[1] = (short)p->mval[0]; /* save x */
}
}
}
@@ -2191,6 +2416,22 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsg
p->pressure = 1.0f;
}
+ /* special eraser modes */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ if (event->shift > 0) {
+ p->flags |= GP_PAINTFLAG_HARD_ERASER;
+ }
+ else {
+ p->flags &= ~GP_PAINTFLAG_HARD_ERASER;
+ }
+ if (event->alt > 0) {
+ p->flags |= GP_PAINTFLAG_STROKE_ERASER;
+ }
+ else {
+ p->flags &= ~GP_PAINTFLAG_STROKE_ERASER;
+ }
+ }
+
/* special exception for start of strokes (i.e. maybe for just a dot) */
if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
@@ -2233,7 +2474,7 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsg
RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
/* apply the current latest drawing point */
- gpencil_draw_apply(op, p, depsgraph);
+ gpencil_draw_apply(C, op, p, depsgraph);
/* force refresh */
ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */
@@ -2251,7 +2492,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
/* try to initialize context data needed while drawing */
if (!gpencil_draw_init(C, op, NULL)) {
- if (op->customdata) MEM_freeN(op->customdata);
+ MEM_SAFE_FREE(op->customdata);
/* printf("\tGP - no valid data\n"); */
return OPERATOR_CANCELLED;
}
@@ -2298,7 +2539,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
}
/* apply this data as necessary now (as per usual) */
- gpencil_draw_apply(op, p, depsgraph);
+ gpencil_draw_apply(C, op, p, depsgraph);
}
RNA_END;
@@ -2324,6 +2565,11 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
if (G.debug & G_DEBUG)
printf("GPencil - Starting Drawing\n");
+ /* support for tablets eraser pen */
+ if (gpencil_is_tablet_eraser_active(event)) {
+ RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER);
+ }
+
/* try to initialize context data needed while drawing */
if (!gpencil_draw_init(C, op, event)) {
if (op->customdata)
@@ -2344,6 +2590,9 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
if (p->paintmode == GP_PAINTMODE_ERASER) {
gpencil_draw_toggle_eraser_cursor(C, p, true);
}
+ else {
+ 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)...
@@ -2357,7 +2606,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
p->status = GP_STATUS_PAINTING;
/* handle the initial drawing - i.e. for just doing a simple dot */
- gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C));
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), 0, 0);
op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
else {
@@ -2366,9 +2615,29 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
+ /* enable paint mode */
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ Object *ob = CTX_data_active_object(C);
+ if (ob && (ob->type == OB_GPENCIL) && ((p->gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0)) {
+ /* Just set paintmode flag... */
+ p->gpd->flag |= GP_DATA_STROKE_PAINTMODE;
+ /* disable other GP modes */
+ p->gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ p->gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ p->gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ /* set workspace mode */
+ ob->restore_mode = ob->mode;
+ ob->mode = OB_MODE_GPENCIL_PAINT;
+ /* redraw mode on screen */
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+ }
+ }
+
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
/* add a modal handler for this operator, so that we can then draw continuous strokes */
WM_event_add_modal_handler(C, op);
+
return OPERATOR_RUNNING_MODAL;
}
@@ -2397,7 +2666,7 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
/* 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, p))
+ if (gp_session_initdata(C, op, p))
gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C));
if (p->status != GP_STATUS_ERROR) {
@@ -2448,6 +2717,76 @@ static void gpencil_move_last_stroke_to_back(bContext *C)
BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
}
+/* add events for missing mouse movements when the artist draw very fast */
+static void gpencil_add_missing_events(bContext *C, wmOperator *op, const wmEvent *event, tGPsdata *p)
+{
+ Brush *brush = p->brush;
+ if (brush->gpencil_settings->input_samples == 0) {
+ return;
+ }
+ RegionView3D *rv3d = p->ar->regiondata;
+ float defaultpixsize = rv3d->pixsize * 1000.0f;
+ int samples = (GP_MAX_INPUT_SAMPLES - brush->gpencil_settings->input_samples + 1);
+ float thickness = (float)brush->size;
+
+ float pt[2], a[2], b[2];
+ float vec[3];
+ float scale = 1.0f;
+
+ /* 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;
+ }
+
+ /* 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;
+ }
+ float factor = ((thickness * dot_factor) / scale) * samples;
+
+ copy_v2fl_v2i(a, p->mvalo);
+ b[0] = event->mval[0] + 1;
+ b[1] = event->mval[1] + 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, CTX_data_depsgraph(C),
+ (int)pt[0], (int)pt[1]);
+ }
+ 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, CTX_data_depsgraph(C),
+ (int)pt[0], (int)pt[1]);
+ }
+ }
+}
+
/* events handling during interactive drawing part of operator */
static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -2488,10 +2827,6 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* is essential for ensuring that they can quickly return to that view
*/
}
- else if ((ELEM(event->type, p->keymodifier)) && (event->val == KM_RELEASE)) {
- /* enable continuous if release D key in mid drawing */
- p->scene->toolsettings->gpencil_flags |= GP_TOOL_FLAG_PAINTSESSIONS_ON;
- }
else if ((event->type == BKEY) && (event->val == KM_RELEASE)) {
/* Add Blank Frame
* - Since this operator is non-modal, we can just call it here, and keep going...
@@ -2510,7 +2845,10 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* exit painting mode (and/or end current stroke)
* NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647]
*/
- if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) {
+ /* 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 */
@@ -2537,10 +2875,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
int sketch = 0;
/* basically, this should be mouse-button up = end stroke
- * BUT what happens next depends on whether we 'painting sessions' is enabled
+ * BUT, polyline drawing is an exception -- all knots should be added during one session
*/
- sketch |= GPENCIL_SKETCH_SESSIONS_ON(p->scene);
- /* polyline drawing is also 'sketching' -- all knots should be added during one session */
sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY);
if (sketch) {
@@ -2585,6 +2921,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
}
+ /* drawing batch cache is dirty now */
+ gp_update_cache(p->gpd);
+
p->status = GP_STATUS_DONE;
estate = OPERATOR_FINISHED;
}
@@ -2689,7 +3028,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
/* handle drawing event */
/* printf("\t\tGP - add point\n"); */
- gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C));
+ gpencil_add_missing_events(C, op, event, p);
+
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), 0, 0);
/* finish painting operation if anything went wrong just now */
if (p->status == GP_STATUS_ERROR) {
@@ -2791,7 +3132,7 @@ void GPENCIL_OT_draw(wmOperatorType *ot)
/* identifiers */
ot->name = "Grease Pencil Draw";
ot->idname = "GPENCIL_OT_draw";
- ot->description = "Make annotations on the active data";
+ ot->description = "Draw a new stroke in the active Grease Pencil Object";
/* api callbacks */
ot->exec = gpencil_draw_exec;
@@ -2811,5 +3152,11 @@ void GPENCIL_OT_draw(wmOperatorType *ot)
/* NOTE: wait for input is enabled by default, so that all UI code can work properly without needing users to know about this */
prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Wait for first click instead of painting immediately");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "disable_straight", false, "No Straight lines", "Disable key for straight lines");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "disable_fill", false, "No Fill Areas", "Disable fill to use stroke as fill boundary");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
new file mode 100644
index 00000000000..ef09c5c3f76
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -0,0 +1,712 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for creating new Grease Pencil primitives (boxes, circles, ...)
+ */
+
+/** \file blender/editors/gpencil/gpencil_primitive.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_main.h"
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "ED_gpencil.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_space_api.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "gpencil_intern.h"
+
+#define MIN_EDGES 2
+#define MAX_EDGES 100
+
+#define IDLE 0
+#define IN_PROGRESS 1
+
+/* ************************************************ */
+/* Core/Shared Utilities */
+
+/* Poll callback for primitive operators */
+static bool gpencil_primitive_add_poll(bContext *C)
+{
+ /* only 3D view */
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype != SPACE_VIEW3D) {
+ return 0;
+ }
+
+ /* need data to create primitive */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ if (gpd == NULL) {
+ return 0;
+ }
+
+ /* only in edit and paint modes
+ * - paint as it's the "drawing/creation mode"
+ * - edit as this is more of an atomic editing operation
+ * (similar to copy/paste), and also for consistency
+ */
+ if ((gpd->flag & (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE)) == 0) {
+ CTX_wm_operator_poll_msg_set(C, "Primitives can only be added in Draw or Edit modes");
+ return 0;
+ }
+
+ /* 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);
+ 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");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* ****************** Primitive Interactive *********************** */
+
+/* Helper: Create internal strokes primitives data */
+static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ Brush *brush;
+
+ /* if brush doesn't exist, create a new one */
+ Paint *paint = BKE_brush_get_gpencil_paint(ts);
+ /* if not exist, create a new one */
+ if (paint->brush == NULL) {
+ /* create new brushes */
+ BKE_brush_gpencil_presets(C);
+ brush = BKE_brush_getactive_gpencil(ts);
+ }
+ else {
+ /* Use the current */
+ brush = BKE_brush_getactive_gpencil(ts);
+ }
+ tgpi->brush = brush;
+
+ /* if layer doesn't exist, create a new one */
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_addnew(tgpi->gpd, DATA_("Primitives"), true);
+ }
+ tgpi->gpl = gpl;
+
+ /* create a new temporary frame */
+ tgpi->gpf = MEM_callocN(sizeof(bGPDframe), "Temp bGPDframe");
+ tgpi->gpf->framenum = tgpi->cframe = cfra_eval;
+
+ /* create new temp stroke */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "Temp bGPDstroke");
+ gps->thickness = 2.0f;
+ gps->inittime = 0.0f;
+
+ /* enable recalculation flag by default */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ /* the polygon must be closed, so enabled cyclic */
+ gps->flag |= GP_STROKE_CYCLIC;
+ gps->flag |= GP_STROKE_3DSPACE;
+
+ gps->mat_nr = BKE_object_material_slot_find_index(tgpi->ob, tgpi->mat) - 1;
+
+ /* allocate memory for storage points, but keep empty */
+ gps->totpoints = 0;
+ gps->points = MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
+ gps->dvert = MEM_callocN(sizeof(MDeformVert), "gp_stroke_weights");
+ /* initialize triangle memory to dummy data */
+ gps->tot_triangles = 0;
+ gps->triangles = NULL;
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* add to strokes */
+ BLI_addtail(&tgpi->gpf->strokes, gps);
+}
+
+/* ----------------------- */
+/* Drawing Callbacks */
+
+/* Drawing callback for modal operator in 3d mode */
+static void gpencil_primitive_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg)
+{
+ tGPDprimitive *tgpi = (tGPDprimitive *)arg;
+ ED_gp_draw_primitives(C, tgpi, REGION_DRAW_POST_VIEW);
+}
+
+/* ----------------------- */
+
+/* Helper: Draw status message while the user is running the operator */
+static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi)
+{
+ Scene *scene = tgpi->scene;
+ char status_str[UI_MAX_DRAW_STR];
+ char msg_str[UI_MAX_DRAW_STR];
+
+ if (tgpi->type == GP_STROKE_BOX) {
+ BLI_strncpy(msg_str, IFACE_("Rectangle: ESC/RMB to cancel, LMB set origin, Enter/LMB to confirm, Shift to square"), UI_MAX_DRAW_STR);
+ }
+ else if (tgpi->type == GP_STROKE_LINE) {
+ BLI_strncpy(msg_str, IFACE_("Line: ESC/RMB to cancel, LMB set origin, Enter/LMB to confirm"), UI_MAX_DRAW_STR);
+ }
+ else {
+ BLI_strncpy(msg_str, IFACE_("Circle: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL to adjust edge number, Shift to square"), UI_MAX_DRAW_STR);
+ }
+
+ if (tgpi->type == GP_STROKE_CIRCLE) {
+ if (hasNumInput(&tgpi->num)) {
+ char str_offs[NUM_STR_REP_LEN];
+
+ outputNumInput(&tgpi->num, str_offs, &scene->unit);
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs);
+ }
+ else {
+ if (tgpi->flag == IN_PROGRESS) {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, (int)tgpi->tot_edges,
+ tgpi->top[0], tgpi->top[1], tgpi->bottom[0], tgpi->bottom[1]);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %d (%d, %d)", msg_str, (int)tgpi->tot_edges,
+ tgpi->bottom[0], tgpi->bottom[1]);
+ }
+ }
+ }
+ else {
+ if (tgpi->flag == IN_PROGRESS) {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: (%d, %d) (%d, %d)", msg_str,
+ tgpi->top[0], tgpi->top[1], tgpi->bottom[0], tgpi->bottom[1]);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: (%d, %d)", msg_str,
+ tgpi->bottom[0], tgpi->bottom[1]);
+ }
+ }
+ ED_workspace_status_text(C, status_str);
+}
+
+/* ----------------------- */
+
+/* create a rectangle */
+static void gp_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D)
+{
+ BLI_assert(tgpi->tot_edges == 4);
+
+ points2D[0].x = tgpi->top[0];
+ points2D[0].y = tgpi->top[1];
+
+ points2D[1].x = tgpi->bottom[0];
+ points2D[1].y = tgpi->top[1];
+
+ points2D[2].x = tgpi->bottom[0];
+ points2D[2].y = tgpi->bottom[1];
+
+ points2D[3].x = tgpi->top[0];
+ points2D[3].y = tgpi->bottom[1];
+}
+
+/* create a line */
+static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D)
+{
+ BLI_assert(tgpi->tot_edges == 2);
+
+ points2D[0].x = tgpi->top[0];
+ points2D[0].y = tgpi->top[1];
+
+ points2D[1].x = tgpi->bottom[0];
+ points2D[1].y = tgpi->bottom[1];
+}
+
+/* create a circle */
+static void gp_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D)
+{
+ const int totpoints = tgpi->tot_edges;
+ const float step = (2.0f * M_PI) / (float)(totpoints);
+ float center[2];
+ float radius[2];
+ float a = 0.0f;
+
+ /* TODO: Use math-lib functions for these? */
+ center[0] = tgpi->top[0] + ((tgpi->bottom[0] - tgpi->top[0]) / 2.0f);
+ center[1] = tgpi->top[1] + ((tgpi->bottom[1] - tgpi->top[1]) / 2.0f);
+ radius[0] = fabsf(((tgpi->bottom[0] - tgpi->top[0]) / 2.0f));
+ radius[1] = fabsf(((tgpi->bottom[1] - tgpi->top[1]) / 2.0f));
+
+ for (int i = 0; i < totpoints; i++) {
+ tGPspoint *p2d = &points2D[i];
+
+ p2d->x = (int)(center[0] + cosf(a) * radius[0]);
+ p2d->y = (int)(center[1] + sinf(a) * radius[1]);
+ a += step;
+ }
+}
+
+/* Helper: Update shape of the stroke */
+static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
+{
+ ToolSettings *ts = tgpi->scene->toolsettings;
+ bGPdata *gpd = tgpi->gpd;
+ bGPDstroke *gps = tgpi->gpf->strokes.first;
+
+ /* realloc points to new size */
+ /* TODO: only do this if the size has changed? */
+ gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * tgpi->tot_edges);
+ gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * tgpi->tot_edges);
+ gps->totpoints = tgpi->tot_edges;
+
+ /* compute screen-space coordinates for points */
+ tGPspoint *points2D = MEM_callocN(sizeof(tGPspoint) * tgpi->tot_edges, "gp primitive points2D");
+ switch (tgpi->type) {
+ case GP_STROKE_BOX:
+ gp_primitive_rectangle(tgpi, points2D);
+ break;
+ case GP_STROKE_LINE:
+ gp_primitive_line(tgpi, points2D);
+ break;
+ case GP_STROKE_CIRCLE:
+ gp_primitive_circle(tgpi, points2D);
+ break;
+ default:
+ break;
+ }
+
+ /* convert screen-coordinates to 3D coordinates */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+ tGPspoint *p2d = &points2D[i];
+
+
+ /* convert screen-coordinates to 3D coordinates */
+ gp_stroke_convertcoords_tpoint(tgpi->scene, tgpi->ar, tgpi->v3d, tgpi->ob, tgpi->gpl, p2d, NULL, &pt->x);
+
+ pt->pressure = 1.0f;
+ pt->strength = tgpi->brush->gpencil_settings->draw_strength;
+ pt->time = 0.0f;
+
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ }
+
+ /* if axis locked, reproject to plane locked */
+ if (tgpi->lock_axis > GP_LOCKAXIS_NONE) {
+ bGPDspoint *tpt = gps->points;
+ float origin[3];
+ ED_gp_get_drawing_reference(tgpi->v3d, tgpi->scene, tgpi->ob, tgpi->gpl,
+ ts->gpencil_v3d_align, origin);
+
+ for (int i = 0; i < gps->totpoints; i++, tpt++) {
+ ED_gp_project_point_to_plane(tgpi->ob, tgpi->rv3d, origin,
+ ts->gp_sculpt.lock_axis - 1,
+ tpt);
+ }
+ }
+
+ /* 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);
+ }
+
+ /* force fill recalc */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* free temp data */
+ MEM_SAFE_FREE(points2D);
+
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+}
+
+/* Update screen and stroke */
+static void gpencil_primitive_update(bContext *C, wmOperator *op, tGPDprimitive *tgpi)
+{
+ /* update indicator in header */
+ gpencil_primitive_status_indicators(C, tgpi);
+ /* apply... */
+ tgpi->type = RNA_enum_get(op->ptr, "type");
+ tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
+ /* update points position */
+ gp_primitive_update_strokes(C, tgpi);
+}
+
+/* ----------------------- */
+
+/* Exit and free memory */
+static void gpencil_primitive_exit(bContext *C, wmOperator *op)
+{
+ tGPDprimitive *tgpi = op->customdata;
+ bGPdata *gpd = tgpi->gpd;
+
+ /* don't assume that operator data exists at all */
+ if (tgpi) {
+ /* remove drawing handler */
+ if (tgpi->draw_handle_3d) {
+ ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d);
+ }
+
+ /* clear status message area */
+ ED_workspace_status_text(C, NULL);
+
+ /* finally, free memory used by temp data */
+ BKE_gpencil_free_strokes(tgpi->gpf);
+ MEM_freeN(tgpi->gpf);
+ MEM_freeN(tgpi);
+ }
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* clear pointer */
+ op->customdata = NULL;
+}
+
+/* Init new temporary primitive data */
+static void gpencil_primitive_init(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ /* create temporary operator data */
+ tGPDprimitive *tgpi = MEM_callocN(sizeof(tGPDprimitive), "GPencil Primitive Data");
+ op->customdata = tgpi;
+
+ /* set current scene and window info */
+ tgpi->scene = scene;
+ tgpi->ob = CTX_data_active_object(C);
+ tgpi->sa = CTX_wm_area(C);
+ tgpi->ar = CTX_wm_region(C);
+ tgpi->rv3d = tgpi->ar->regiondata;
+ tgpi->v3d = tgpi->sa->spacedata.first;
+ tgpi->depsgraph = CTX_data_depsgraph(C);
+ tgpi->win = CTX_wm_window(C);
+
+ /* set current frame number */
+ tgpi->cframe = cfra_eval;
+
+ /* set GP datablock */
+ tgpi->gpd = gpd;
+
+ /* getcolor info */
+ tgpi->mat = BKE_gpencil_material_ensure(bmain, tgpi->ob);
+
+ /* set parameters */
+ tgpi->type = RNA_enum_get(op->ptr, "type");
+
+ /* if circle set default to 32 */
+ if (tgpi->type == GP_STROKE_CIRCLE) {
+ RNA_int_set(op->ptr, "edges", 32);
+ }
+ else if(tgpi->type == GP_STROKE_BOX) {
+ RNA_int_set(op->ptr, "edges", 4);
+ }
+ else { /* LINE */
+ RNA_int_set(op->ptr, "edges", 2);
+ }
+
+ tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
+ tgpi->flag = IDLE;
+
+ tgpi->lock_axis = ts->gp_sculpt.lock_axis;
+
+ /* set temp layer, frame and stroke */
+ gp_primitive_set_initdata(C, tgpi);
+}
+
+/* ----------------------- */
+
+/* Invoke handler: Initialize the operator */
+static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ wmWindow *win = CTX_wm_window(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ tGPDprimitive *tgpi = NULL;
+
+ /* initialize operator runtime data */
+ gpencil_primitive_init(C, op);
+ tgpi = op->customdata;
+
+ /* if in tools region, wait till we get to the main (3d-space)
+ * region before allowing drawing to take place.
+ */
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+
+ /* Enable custom drawing handlers */
+ tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_primitive_draw_3d, tgpi, REGION_DRAW_POST_VIEW);
+
+ /* set cursor to indicate modal */
+ WM_cursor_modal_set(win, BC_CROSSCURSOR);
+
+ /* update sindicator in header */
+ gpencil_primitive_status_indicators(C, tgpi);
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* add a modal handler for this operator */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Helper to complete a primitive */
+static void gpencil_primitive_done(bContext *C, wmOperator *op, wmWindow *win, tGPDprimitive *tgpi)
+{
+ bGPDframe *gpf;
+ bGPDstroke *gps;
+
+ /* return to normal cursor and header status */
+ ED_workspace_status_text(C, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* insert keyframes as required... */
+ gpf = BKE_gpencil_layer_getframe(tgpi->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW);
+
+ /* prepare stroke to get transfered */
+ gps = tgpi->gpf->strokes.first;
+ if (gps) {
+ gps->thickness = tgpi->brush->size;
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ }
+
+ /* transfer stroke from temporary buffer to the actual frame */
+ BLI_movelisttolist(&gpf->strokes, &tgpi->gpf->strokes);
+ BLI_assert(BLI_listbase_is_empty(&tgpi->gpf->strokes));
+
+ /* clean up temp data */
+ gpencil_primitive_exit(C, op);
+}
+
+/* Modal handler: Events handling during interactive part */
+static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGPDprimitive *tgpi = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+ const bool has_numinput = hasNumInput(&tgpi->num);
+
+ switch (event->type) {
+ case LEFTMOUSE:
+ if ((event->val == KM_PRESS) && (tgpi->flag == IDLE)) {
+ /* start drawing primitive */
+ /* TODO: Ignore if not in main region yet */
+ tgpi->flag = IN_PROGRESS;
+
+ tgpi->top[0] = event->mval[0];
+ tgpi->top[1] = event->mval[1];
+
+ tgpi->bottom[0] = event->mval[0];
+ tgpi->bottom[1] = event->mval[1];
+ }
+ else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
+ /* stop drawing primitive */
+ tgpi->flag = IDLE;
+ gpencil_primitive_done(C, op, win, tgpi);
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+ else {
+ if (G.debug & G_DEBUG) {
+ printf("GP Add Primitive Modal: LEFTMOUSE %d, Status = %d\n", event->val, tgpi->flag);
+ }
+ }
+ break;
+ case RETKEY: /* confirm */
+ {
+ tgpi->flag = IDLE;
+ gpencil_primitive_done(C, op, win, tgpi);
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+
+ case ESCKEY: /* cancel */
+ case RIGHTMOUSE:
+ {
+ /* return to normal cursor and header status */
+ ED_workspace_status_text(C, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* clean up temp data */
+ gpencil_primitive_exit(C, op);
+
+ /* canceled! */
+ return OPERATOR_CANCELLED;
+ }
+
+ case WHEELUPMOUSE:
+ {
+ if (tgpi->type == GP_STROKE_CIRCLE) {
+ tgpi->tot_edges = tgpi->tot_edges + 1;
+ CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
+
+ /* update screen */
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case WHEELDOWNMOUSE:
+ {
+ if (tgpi->type == GP_STROKE_CIRCLE) {
+ tgpi->tot_edges = tgpi->tot_edges - 1;
+ CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
+
+ /* update screen */
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case MOUSEMOVE: /* calculate new position */
+ {
+ /* only handle mousemove if not doing numinput */
+ if (has_numinput == false) {
+ /* update position of mouse */
+ tgpi->bottom[0] = event->mval[0];
+ tgpi->bottom[1] = event->mval[1];
+ if (tgpi->flag == IDLE) {
+ tgpi->top[0] = event->mval[0];
+ tgpi->top[1] = event->mval[1];
+ }
+ /* Keep square if shift key */
+ if (event->shift) {
+ tgpi->bottom[1] = tgpi->top[1] - (tgpi->bottom[0] - tgpi->top[0]);
+ }
+ /* update screen */
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ default:
+ {
+ if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) {
+ float value;
+
+ /* Grab data from numeric input, and store this new value (the user see an int) */
+ value = tgpi->tot_edges;
+ applyNumInput(&tgpi->num, &value);
+ tgpi->tot_edges = value;
+
+ CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
+
+ /* update screen */
+ gpencil_primitive_update(C, op, tgpi);
+
+ break;
+ }
+ else {
+ /* unhandled event - allow to pass through */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
+ }
+ }
+
+ /* still running... */
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Cancel handler */
+static void gpencil_primitive_cancel(bContext *C, wmOperator *op)
+{
+ /* this is just a wrapper around exit() */
+ gpencil_primitive_exit(C, op);
+}
+
+void GPENCIL_OT_primitive(wmOperatorType *ot)
+{
+ static EnumPropertyItem primitive_type[] = {
+ { GP_STROKE_BOX, "BOX", 0, "Box", "" },
+ { GP_STROKE_LINE, "LINE", 0, "Line", "" },
+ { GP_STROKE_CIRCLE, "CIRCLE", 0, "Circle", "" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+ /* identifiers */
+ ot->name = "Grease Pencil Shapes";
+ ot->idname = "GPENCIL_OT_primitive";
+ ot->description = "Create predefined grease pencil stroke shapes";
+
+ /* callbacks */
+ ot->invoke = gpencil_primitive_invoke;
+ ot->modal = gpencil_primitive_modal;
+ ot->cancel = gpencil_primitive_cancel;
+ ot->poll = gpencil_primitive_add_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ RNA_def_int(ot->srna, "edges", 4, MIN_EDGES, MAX_EDGES, "Edges", "Number of polygon edges", MIN_EDGES, MAX_EDGES);
+ RNA_def_enum(ot->srna, "type", primitive_type, GP_STROKE_BOX, "Type", "Type of shape");
+}
+
+/* *************************************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index dd556e99264..9386bfb3333 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -43,6 +43,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
#include "DNA_screen_types.h"
#include "DNA_object_types.h"
@@ -62,6 +63,9 @@
#include "ED_gpencil.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "gpencil_intern.h"
/* ********************************************** */
@@ -71,8 +75,8 @@ static bool gpencil_select_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- /* we just need some visible strokes, and to be in editmode */
- if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
+ /* 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? */
if (gpd->layers.first)
return true;
@@ -94,6 +98,11 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
/* for "toggle", test for existing selected strokes */
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
@@ -180,6 +189,11 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op)
}
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -213,6 +227,11 @@ static int gpencil_select_linked_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
/* select all points in selected strokes */
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
{
@@ -228,6 +247,11 @@ static int gpencil_select_linked_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -248,6 +272,86 @@ void GPENCIL_OT_select_linked(wmOperatorType *ot)
}
/* ********************************************** */
+/* Select Alternate */
+
+static int gpencil_select_alternate_exec(bContext *C, wmOperator *op)
+{
+ const bool unselect_ends = RNA_boolean_get(op->ptr, "unselect_ends");
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* select all points in selected strokes */
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) {
+ bGPDspoint *pt;
+ int row = 0;
+ int start = 0;
+ if (unselect_ends) {
+ start = 1;
+ }
+
+ for (int i = start; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ if ((row % 2) == 0) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ else {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ row++;
+ }
+
+ /* unselect start and end points */
+ if (unselect_ends) {
+ pt = &gps->points[0];
+ pt->flag &= ~GP_SPOINT_SELECT;
+
+ pt = &gps->points[gps->totpoints - 1];
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_select_alternate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Alternated";
+ ot->idname = "GPENCIL_OT_select_alternate";
+ ot->description = "Select alternative points in same strokes as already selected points";
+
+ /* callbacks */
+ ot->exec = gpencil_select_alternate_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "unselect_ends", true, "Unselect Ends", "Do not select the first and last point of the stroke");
+}
+
+/* ********************************************** */
/* Select Grouped */
typedef enum eGP_SelectGrouped {
@@ -266,11 +370,12 @@ typedef enum eGP_SelectGrouped {
/* On each visible layer, check for selected strokes - if found, select all others */
static void gp_select_same_layer(bContext *C)
{
- Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0);
bGPDstroke *gps;
bool found = false;
@@ -309,10 +414,7 @@ static void gp_select_same_layer(bContext *C)
/* Select all strokes with same colors as selected ones */
static void gp_select_same_color(bContext *C)
{
- /* First, build set containing all the colors of selected strokes
- * - We use the palette names, so that we can select all strokes with one
- * (potentially missing) color, and remap them to something else
- */
+ /* First, build set containing all the colors of selected strokes */
GSet *selected_colors = BLI_gset_str_new("GP Selected Colors");
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
@@ -321,7 +423,7 @@ static void gp_select_same_color(bContext *C)
/* add instead of insert here, otherwise the uniqueness check gets skipped,
* and we get many duplicate entries...
*/
- BLI_gset_add(selected_colors, gps->colorname);
+ BLI_gset_add(selected_colors, &gps->mat_nr);
}
}
CTX_DATA_END;
@@ -329,7 +431,7 @@ static void gp_select_same_color(bContext *C)
/* Second, select any visible stroke that uses these colors */
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
{
- if (BLI_gset_haskey(selected_colors, gps->colorname)) {
+ if (BLI_gset_haskey(selected_colors, &gps->mat_nr)) {
/* select this stroke */
bGPDspoint *pt;
int i;
@@ -342,6 +444,11 @@ static void gp_select_same_color(bContext *C)
}
}
CTX_DATA_END;
+
+ /* free memomy */
+ if (selected_colors != NULL) {
+ BLI_gset_free(selected_colors, NULL);
+ }
}
@@ -350,6 +457,11 @@ static void gp_select_same_color(bContext *C)
static int gpencil_select_grouped_exec(bContext *C, wmOperator *op)
{
eGP_SelectGrouped mode = RNA_enum_get(op->ptr, "type");
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
switch (mode) {
case GP_SEL_SAME_LAYER:
@@ -365,6 +477,11 @@ static int gpencil_select_grouped_exec(bContext *C, wmOperator *op)
}
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -399,6 +516,12 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot)
static int gpencil_select_first_exec(bContext *C, wmOperator *op)
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes");
const bool extend = RNA_boolean_get(op->ptr, "extend");
@@ -429,6 +552,11 @@ static int gpencil_select_first_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -459,6 +587,12 @@ void GPENCIL_OT_select_first(wmOperatorType *ot)
static int gpencil_select_last_exec(bContext *C, wmOperator *op)
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes");
const bool extend = RNA_boolean_get(op->ptr, "extend");
@@ -489,6 +623,11 @@ static int gpencil_select_last_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -519,6 +658,12 @@ void GPENCIL_OT_select_last(wmOperatorType *ot)
static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
{
if (gps->flag & GP_STROKE_SELECT) {
@@ -565,6 +710,11 @@ static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_END;
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -589,6 +739,12 @@ void GPENCIL_OT_select_more(wmOperatorType *ot)
static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
{
if (gps->flag & GP_STROKE_SELECT) {
@@ -636,6 +792,11 @@ static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_END;
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -665,7 +826,7 @@ void GPENCIL_OT_select_less(wmOperatorType *ot)
static bool gp_stroke_do_circle_sel(
bGPDstroke *gps, GP_SpaceConversion *gsc,
const int mx, const int my, const int radius,
- const bool select, rcti *rect, const bool parented, float diff_mat[4][4])
+ const bool select, rcti *rect, float diff_mat[4][4])
{
bGPDspoint *pt1, *pt2;
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
@@ -673,14 +834,9 @@ static bool gp_stroke_do_circle_sel(
bool changed = false;
if (gps->totpoints == 1) {
- if (!parented) {
- gp_point_to_xy(gsc, gps, gps->points, &x0, &y0);
- }
- else {
- bGPDspoint pt_temp;
- gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
- gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0);
- }
+ bGPDspoint pt_temp;
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0);
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
@@ -708,18 +864,12 @@ static bool gp_stroke_do_circle_sel(
/* get points to work with */
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
- if (!parented) {
- gp_point_to_xy(gsc, gps, pt1, &x0, &y0);
- gp_point_to_xy(gsc, gps, pt2, &x1, &y1);
- }
- else {
- bGPDspoint npt;
- gp_point_to_parent_space(pt1, diff_mat, &npt);
- gp_point_to_xy(gsc, gps, &npt, &x0, &y0);
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &x0, &y0);
- gp_point_to_parent_space(pt2, diff_mat, &npt);
- gp_point_to_xy(gsc, gps, &npt, &x1, &y1);
- }
+ gp_point_to_parent_space(pt2, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &x1, &y1);
/* check that point segment of the boundbox of the selection stroke */
if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
@@ -763,6 +913,12 @@ static bool gp_stroke_do_circle_sel(
static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
ScrArea *sa = CTX_wm_area(C);
const int mx = RNA_int_get(op->ptr, "x");
@@ -798,13 +954,17 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
changed |= gp_stroke_do_circle_sel(
- gps, &gsc, mx, my, radius, select, &rect,
- (gpl->parent != NULL), diff_mat);
+ gps, &gsc, mx, my, radius, select, &rect, diff_mat);
}
GP_EDITABLE_STROKES_END;
/* updates */
if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
}
@@ -837,10 +997,11 @@ void GPENCIL_OT_select_circle(wmOperatorType *ot)
static int gpencil_border_select_exec(bContext *C, wmOperator *op)
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
ScrArea *sa = CTX_wm_area(C);
const bool select = !RNA_boolean_get(op->ptr, "deselect");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool extend = RNA_boolean_get(op->ptr, "extend") && ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0);
GP_SpaceConversion gsc = {NULL};
rcti rect = {0};
@@ -888,14 +1049,9 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op)
int x0, y0;
/* convert point coords to screenspace */
- if (gpl->parent == NULL) {
- gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
- }
- else {
- bGPDspoint pt2;
- gp_point_to_parent_space(pt, diff_mat, &pt2);
- gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0);
- }
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0);
/* test if in selection rect */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0)) {
@@ -915,8 +1071,20 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op)
}
GP_EDITABLE_STROKES_END;
+ /* if paint mode,delete selected points */
+ if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
+ gp_delete_selected_point_wrap(C);
+ changed = true;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ }
+
/* updates */
if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
}
@@ -950,10 +1118,11 @@ void GPENCIL_OT_select_border(wmOperatorType *ot)
static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
GP_SpaceConversion gsc = {NULL};
rcti rect = {0};
- const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool extend = RNA_boolean_get(op->ptr, "extend") && ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0);
const bool select = !RNA_boolean_get(op->ptr, "deselect");
int mcords_tot;
@@ -997,14 +1166,9 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
int x0, y0;
/* convert point coords to screenspace */
- if (gpl->parent == NULL) {
- gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
- }
- else {
- bGPDspoint pt2;
- gp_point_to_parent_space(pt, diff_mat, &pt2);
- gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0);
- }
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0);
/* test if in lasso boundbox + within the lasso noose */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0) &&
BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX))
@@ -1028,8 +1192,20 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
/* cleanup */
MEM_freeN((void *)mcords);
+ /* if paint mode,delete selected points */
+ if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
+ gp_delete_selected_point_wrap(C);
+ changed = true;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ }
+
/* updates */
if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
}
@@ -1061,6 +1237,7 @@ void GPENCIL_OT_select_lasso(wmOperatorType *ot)
static int gpencil_select_exec(bContext *C, wmOperator *op)
{
ScrArea *sa = CTX_wm_area(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
/* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */
const float radius = 0.75f * U.widget_unit;
@@ -1102,14 +1279,9 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int xy[2];
- if (gpl->parent == NULL) {
- gp_point_to_xy(&gsc, gps, pt, &xy[0], &xy[1]);
- }
- else {
- bGPDspoint pt2;
- gp_point_to_parent_space(pt, diff_mat, &pt2);
- gp_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]);
- }
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]);
/* do boundbox check first */
if (!ELEM(V2D_IS_CLIPPED, xy[0], xy[1])) {
@@ -1197,6 +1369,11 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* updates */
if (hit_point != NULL) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
}
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index d35df8bc380..708d8f37e58 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
#include "DNA_listBase.h"
#include "DNA_windowmanager_types.h"
@@ -51,6 +52,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "DEG_depsgraph.h"
+
#include "gpencil_intern.h"
typedef struct bGPundonode {
@@ -111,6 +114,9 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name)
}
}
}
+ /* drawing batch cache is dirty now */
+ DEG_id_tag_update(&new_gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ new_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
}
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 8b65855f7c4..7262c537321 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -40,7 +40,9 @@
#include "BLT_translation.h"
#include "BLI_rand.h"
+#include "DNA_meshdata_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -48,9 +50,13 @@
#include "DNA_view3d_types.h"
#include "BKE_action.h"
+#include "BKE_main.h"
+#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
-#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_material.h"
#include "BKE_tracking.h"
#include "WM_api.h"
@@ -65,8 +71,14 @@
#include "ED_gpencil.h"
#include "ED_clip.h"
#include "ED_view3d.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "gpencil_intern.h"
@@ -76,7 +88,7 @@
/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it,
* when context info is not available.
*/
-bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob, PointerRNA *ptr)
+bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, ScrArea *sa, Scene *scene, Object *ob, PointerRNA *r_ptr)
{
/* if there's an active area, check if the particular editor may
* have defined any special Grease Pencil context for editing...
@@ -85,26 +97,37 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
SpaceLink *sl = sa->spacedata.first;
switch (sa->spacetype) {
- case SPACE_VIEW3D: /* 3D-View */
+ /* XXX: Should we reduce reliance on context.gpencil_data for these cases? */
+ case SPACE_BUTS: /* properties */
+ case SPACE_INFO: /* header info (needed after workspaces merge) */
{
- BLI_assert(scene && ELEM(scene->toolsettings->gpencil_src,
- GP_TOOL_SOURCE_SCENE, GP_TOOL_SOURCE_OBJECT));
+ if (ob && (ob->type == OB_GPENCIL)) {
+ /* GP Object */
+ if (r_ptr) RNA_id_pointer_create(&ob->id, r_ptr);
+ return (bGPdata **)&ob->data;
+ }
+ else {
+ return NULL;
+ }
- if (scene->toolsettings->gpencil_src == GP_TOOL_SOURCE_OBJECT) {
- /* legacy behaviour for usage with old addons requiring object-linked to objects */
+ break;
+ }
- /* just in case no active/selected object... */
- if (ob && (ob->flag & SELECT)) {
- /* for now, as long as there's an object, default to using that in 3D-View */
- if (ptr) RNA_id_pointer_create(&ob->id, ptr);
- return &ob->gpd;
- }
- /* else: defaults to scene... */
+ case SPACE_TOPBAR: /* Topbar (needed after topbar merge) */
+ case SPACE_VIEW3D: /* 3D-View */
+ {
+ if (ob && (ob->type == OB_GPENCIL)) {
+ /* GP Object */
+ if (r_ptr) RNA_id_pointer_create(&ob->id, r_ptr);
+ return (bGPdata **)&ob->data;
}
else {
- if (ptr) RNA_id_pointer_create(&scene->id, ptr);
+ /* Annotations */
+ /* XXX: */
+ if (r_ptr) RNA_id_pointer_create(&scene->id, r_ptr);
return &scene->gpd;
}
+
break;
}
case SPACE_NODE: /* Nodes Editor */
@@ -114,7 +137,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
/* return the GP data for the active node block/node */
if (snode && snode->nodetree) {
/* for now, as long as there's an active node tree, default to using that in the Nodes Editor */
- if (ptr) RNA_id_pointer_create(&snode->nodetree->id, ptr);
+ if (r_ptr) RNA_id_pointer_create(&snode->nodetree->id, r_ptr);
return &snode->nodetree->gpd;
}
@@ -127,7 +150,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
/* for now, Grease Pencil data is associated with the space (actually preview region only) */
/* XXX our convention for everything else is to link to data though... */
- if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, ptr);
+ if (r_ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, r_ptr);
return &sseq->gpd;
}
case SPACE_IMAGE: /* Image/UV Editor */
@@ -136,7 +159,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
/* for now, Grease Pencil data is associated with the space... */
/* XXX our convention for everything else is to link to data though... */
- if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, ptr);
+ if (r_ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, r_ptr);
return &sima->gpd;
}
case SPACE_CLIP: /* Nodes Editor */
@@ -151,15 +174,11 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
if (!track)
return NULL;
- if (ptr)
- RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, ptr);
-
+ if (r_ptr) RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, r_ptr);
return &track->gpd;
}
else {
- if (ptr)
- RNA_id_pointer_create(&clip->id, ptr);
-
+ if (r_ptr) RNA_id_pointer_create(&clip->id, r_ptr);
return &clip->gpd;
}
}
@@ -170,79 +189,102 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
}
}
- /* just fall back on the scene's GP data */
- if (ptr) RNA_id_pointer_create((ID *)scene, ptr);
- return (scene) ? &scene->gpd : NULL;
+ return NULL;
}
/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
-bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
+bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
{
ID *screen_id = (ID *)CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
ScrArea *sa = CTX_wm_area(C);
Object *ob = CTX_data_active_object(C);
- return ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, ptr);
+ return ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, r_ptr);
}
/* -------------------------------------------------------- */
/* Get the active Grease Pencil datablock, when context is not available */
-bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob)
+bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, ScrArea *sa, Scene *scene, Object *ob)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, NULL);
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
-/* Get the active Grease Pencil datablock */
+/**
+ * Get the active Grease Pencil datablock
+ * \note This is the original (bmain) copy of the datablock, stored in files.
+ * Do not use for reading evaluated copies of GP Objects data
+ */
bGPdata *ED_gpencil_data_get_active(const bContext *C)
{
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
+/**
+ * Get the evaluated copy of the active Grease Pencil datablock (where applicable)
+ * - For the 3D View (i.e. "GP Objects"), this gives the evaluated copy of the GP datablock
+ * (i.e. a copy of the active GP datablock for the active object, where modifiers have been
+ * applied). This is needed to correctly work with "Copy-on-Write"
+ * - For all other editors (i.e. "GP Annotations"), this just gives the active datablock
+ * like for ED_gpencil_data_get_active()
+ */
+bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
+{
+ ID *screen_id = (ID *)CTX_wm_screen(C);
+ ScrArea *sa = CTX_wm_area(C);
+
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob = CTX_data_active_object(C);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+
+ /* if (ob && ob->type == OB_GPENCIL) BLI_assert(ob_eval->data == DEG_get_evaluated_id(ob->data)); */
+ return ED_gpencil_data_get_active_direct(screen_id, sa, scene_eval, ob_eval);
+}
+
+/* -------------------------------------------------------- */
+
+/**
+ * Utility to check whether the r_ptr output of ED_gpencil_data_get_pointers()
+ * is for annotation usage.
+ */
+bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
+{
+ /* Key Assumption: If the pointer is an object, we're dealing with a GP Object's data.
+ * Otherwise, the GP datablock is being used for annotations (i.e. everywhere else)
+ */
+ return ((owner_ptr) && (owner_ptr->type != &RNA_Object));
+}
+
/* -------------------------------------------------------- */
// XXX: this should be removed... We really shouldn't duplicate logic like this!
-bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, ViewLayer *view_layer)
+bGPdata *ED_gpencil_data_get_active_v3d(ViewLayer *view_layer)
{
Base *base = view_layer->basact;
bGPdata *gpd = NULL;
+
/* We have to make sure active object is actually visible and selected, else we must use default scene gpd,
* to be consistent with ED_gpencil_data_get_active's behavior.
*/
-
if (base && TESTBASE(base)) {
- gpd = base->object->gpd;
+ if (base->object->type == OB_GPENCIL)
+ gpd = base->object->data;
}
- return gpd ? gpd : scene->gpd;
+ return gpd ? gpd : NULL;
}
/* ******************************************************** */
/* Keyframe Indicator Checks */
/* Check whether there's an active GP keyframe on the current frame */
-bool ED_gpencil_has_keyframe_v3d(Scene *scene, Object *ob, int cfra)
+bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
{
- /* just check both for now... */
- // XXX: this could get confusing (e.g. if only on the object, but other places don't show this)
- if (scene->gpd) {
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(scene->gpd);
- if (gpl) {
- if (gpl->actframe) {
- // XXX: assumes that frame has been fetched already
- return (gpl->actframe->framenum == cfra);
- }
- else {
- /* XXX: disabled as could be too much of a penalty */
- /* return BKE_gpencil_layer_find_frame(gpl, cfra); */
- }
- }
- }
-
- if (ob && ob->gpd) {
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->gpd);
+ if (ob && ob->data && (ob->type == OB_GPENCIL)) {
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->data);
if (gpl) {
if (gpl->actframe) {
// XXX: assumes that frame has been fetched already
@@ -281,28 +323,13 @@ bool gp_active_layer_poll(bContext *C)
bool gp_active_brush_poll(bContext *C)
{
ToolSettings *ts = CTX_data_tool_settings(C);
- bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
-
- return (brush != NULL);
-}
-
-/* poll callback for checking if there is an active palette */
-bool gp_active_palette_poll(bContext *C)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
-
- return (palette != NULL);
-}
-
-/* poll callback for checking if there is an active palette color */
-bool gp_active_palettecolor_poll(bContext *C)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
-
- return (palcolor != NULL);
+ Paint *paint = &ts->gp_paint->paint;
+ if (paint) {
+ return (paint->brush != NULL);
+ }
+ else {
+ return false;
+ }
}
/* ******************************************************** */
@@ -360,7 +387,7 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(
/* Create new layer */
/* TODO: have some way of specifying that we don't want this? */
{
- /* active Keying Set */
+ /* "New Layer" entry */
item_tmp.identifier = "__CREATE__";
item_tmp.name = "New Layer";
item_tmp.value = -1;
@@ -392,7 +419,6 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(
}
-
/* ******************************************************** */
/* Brush Tool Core */
@@ -426,7 +452,7 @@ bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
/* Stroke Validity Testing */
/* Check whether given stroke can be edited given the supplied context */
-// XXX: do we need additional flags for screenspace vs dataspace?
+/* TODO: do we need additional flags for screenspace vs dataspace? */
bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps)
{
/* sanity check */
@@ -436,7 +462,7 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps)
/* filter stroke types by flags + spacetype */
if (gps->flag & GP_STROKE_3DSPACE) {
/* 3D strokes - only in 3D view */
- return (sa->spacetype == SPACE_VIEW3D);
+ return ((sa->spacetype == SPACE_VIEW3D) || (sa->spacetype == SPACE_BUTS));
}
else if (gps->flag & GP_STROKE_2DIMAGE) {
/* Special "image" strokes - only in Image Editor */
@@ -460,59 +486,21 @@ bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
}
/* Check whether given stroke can be edited for the current color */
-bool ED_gpencil_stroke_color_use(const bGPDlayer *gpl, const bGPDstroke *gps)
+bool ED_gpencil_stroke_color_use(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps)
{
/* check if the color is editable */
- bGPDpalettecolor *palcolor = gps->palcolor;
- if (palcolor != NULL) {
- if (palcolor->flag & PC_COLOR_HIDE)
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+
+ if (gp_style != NULL) {
+ if (gp_style->flag & GP_STYLE_COLOR_HIDE)
return false;
- if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED))
+ if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_STYLE_COLOR_LOCKED))
return false;
}
return true;
}
-/* Get palette color or create a new one */
-bGPDpalettecolor *ED_gpencil_stroke_getcolor(bGPdata *gpd, bGPDstroke *gps)
-{
- bGPDpalette *palette;
- bGPDpalettecolor *palcolor;
-
- if ((gps->palcolor != NULL) && ((gps->flag & GP_STROKE_RECALC_COLOR) == 0))
- return gps->palcolor;
-
- /* get palette */
- palette = BKE_gpencil_palette_getactive(gpd);
- if (palette == NULL) {
- palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true);
- }
- /* get color */
- palcolor = BKE_gpencil_palettecolor_getbyname(palette, gps->colorname);
- if (palcolor == NULL) {
- if (gps->palcolor == NULL) {
- palcolor = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
- /* set to a different color */
- ARRAY_SET_ITEMS(palcolor->color, 1.0f, 0.0f, 1.0f, 0.9f);
- }
- else {
- palcolor = BKE_gpencil_palettecolor_addnew(palette, gps->colorname, true);
- /* set old color and attributes */
- bGPDpalettecolor *gpscolor = gps->palcolor;
- copy_v4_v4(palcolor->color, gpscolor->color);
- copy_v4_v4(palcolor->fill, gpscolor->fill);
- palcolor->flag = gpscolor->flag;
- }
- }
-
- /* clear flag and set pointer */
- gps->flag &= ~GP_STROKE_RECALC_COLOR;
- gps->palcolor = palcolor;
-
- return palcolor;
-}
-
/* ******************************************************** */
/* Space Conversion */
@@ -573,9 +561,9 @@ void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *
}
/**
- * Change points position relative to parent object
+ * Change position relative to parent object
*/
-void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps)
+void gp_apply_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps)
{
bGPDspoint *pt;
int i;
@@ -585,7 +573,7 @@ void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps)
float inverse_diff_mat[4][4];
float fpt[3];
- ED_gpencil_parent_location(gpl, diff_mat);
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
for (i = 0; i < gps->totpoints; i++) {
@@ -598,14 +586,14 @@ void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps)
/**
* Change point position relative to parent object
*/
-void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt)
+void gp_apply_parent_point(Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDspoint *pt)
{
/* undo matrix */
float diff_mat[4][4];
float inverse_diff_mat[4][4];
float fpt[3];
- ED_gpencil_parent_location(gpl, diff_mat);
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
@@ -770,194 +758,259 @@ bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, Scene *scene, const float screen
}
/**
- * Apply smooth to stroke point
- * \param gps Stroke to smooth
- * \param i Point index
- * \param inf Amount of smoothing to apply
- * \param affect_pressure Apply smoothing to pressure values too?
+ * Convert tGPspoint (temporary 2D/screenspace point data used by GP modal operators)
+ * to 3D coordinates.
+ *
+ * \param point2D: The screenspace 2D point data to convert
+ * \param depth: Depth array (via ED_view3d_autodist_depth())
+ * \param[out] r_out: The resulting 2D point data
*/
-bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure)
+void gp_stroke_convertcoords_tpoint(
+ Scene *scene, ARegion *ar, View3D *v3d,
+ Object *ob, bGPDlayer *gpl,
+ const tGPspoint *point2D, float *depth,
+ float r_out[3])
{
- bGPDspoint *pt = &gps->points[i];
- float pressure = 0.0f;
- float sco[3] = {0.0f};
-
- /* Do nothing if not enough points to smooth out */
- if (gps->totpoints <= 2) {
- return false;
- }
+ ToolSettings *ts = scene->toolsettings;
+ const int mval[2] = {point2D->x, point2D->y};
- /* Only affect endpoints by a fraction of the normal strength,
- * to prevent the stroke from shrinking too much
- */
- if ((i == 0) || (i == gps->totpoints - 1)) {
- inf *= 0.1f;
+ if ((depth != NULL) && (ED_view3d_autodist_simple(ar, mval, r_out, 0, depth))) {
+ /* projecting onto 3D-Geometry
+ * - nothing more needs to be done here, since view_autodist_simple() has already done it
+ */
}
-
- /* Compute smoothed coordinate by taking the ones nearby */
- /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */
- {
- // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total)
- const int steps = 2;
- const float average_fac = 1.0f / (float)(steps * 2 + 1);
- int step;
-
- /* add the point itself */
- madd_v3_v3fl(sco, &pt->x, average_fac);
-
- if (affect_pressure) {
- pressure += pt->pressure * average_fac;
+ else {
+ float mval_f[2] = {(float)point2D->x, (float)point2D->y};
+ float mval_prj[2];
+ float rvec[3], dvec[3];
+ float zfac;
+
+ /* Current method just converts each point in screen-coordinates to
+ * 3D-coordinates using the 3D-cursor as reference.
+ */
+ ED_gp_get_drawing_reference(v3d, scene, ob, gpl, ts->gpencil_v3d_align, rvec);
+ zfac = ED_view3d_calc_zfac(ar->regiondata, rvec, NULL);
+
+ if (ED_view3d_project_float_global(ar, 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(ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(r_out, rvec, dvec);
}
+ else {
+ zero_v3(r_out);
+ }
+ }
+}
- /* n-steps before/after current point */
- // XXX: review how the endpoints are treated by this algorithm
- // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight
- for (step = 1; step <= steps; step++) {
- bGPDspoint *pt1, *pt2;
- int before = i - step;
- int after = i + step;
-
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
-
- pt1 = &gps->points[before];
- pt2 = &gps->points[after];
-
- /* add both these points to the average-sum (s += p[i]/n) */
- madd_v3_v3fl(sco, &pt1->x, average_fac);
- madd_v3_v3fl(sco, &pt2->x, average_fac);
-
-#if 0
- /* XXX: Disabled because get weird result */
- /* do pressure too? */
- if (affect_pressure) {
- pressure += pt1->pressure * average_fac;
- pressure += pt2->pressure * average_fac;
+/**
+ * Get drawing reference point for conversion or projection of the stroke
+ * \param[out] r_vec : Reference point found
+ */
+void ED_gp_get_drawing_reference(
+ View3D *v3d, Scene *scene, Object *ob, bGPDlayer *UNUSED(gpl),
+ char align_flag, float r_vec[3])
+{
+ const float *fp = ED_view3d_cursor3d_get(scene, v3d)->location;
+
+ /* if using a gpencil object at cursor mode, can use the location of the object */
+ if (align_flag & GP_PROJECT_VIEWSPACE) {
+ if (ob && (ob->type == OB_GPENCIL)) {
+ /* fallback (no strokes) - use cursor or object location */
+ if (align_flag & GP_PROJECT_CURSOR) {
+ /* use 3D-cursor */
+ copy_v3_v3(r_vec, fp);
+ }
+ else {
+ /* use object location */
+ copy_v3_v3(r_vec, ob->obmat[3]);
}
-#endif
}
}
-
- /* Based on influence factor, blend between original and optimal smoothed coordinate */
- interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
-
-#if 0
- /* XXX: Disabled because get weird result */
- if (affect_pressure) {
- pt->pressure = pressure;
+ else {
+ /* use 3D-cursor */
+ copy_v3_v3(r_vec, fp);
}
-#endif
-
- return true;
}
+
/**
-* Apply smooth for strength to stroke point
-* \param gps Stroke to smooth
-* \param i Point index
-* \param inf Amount of smoothing to apply
-*/
-bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf)
+ * Reproject all points of the stroke to a plane locked to axis to avoid stroke offset
+ */
+void ED_gp_project_stroke_to_plane(Object *ob, RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis)
{
- bGPDspoint *ptb = &gps->points[i];
-
- /* Do nothing if not enough points */
- if (gps->totpoints <= 2) {
- return false;
+ float plane_normal[3];
+ float vn[3];
+
+ float ray[3];
+ float rpoint[3];
+
+ /* normal vector for a plane locked to axis */
+ zero_v3(plane_normal);
+ if (axis < 0) {
+ /* if the axis is not locked, need a vector to the view direction
+ * in order to get the right size of the stroke.
+ */
+ ED_view3d_global_to_vector(rv3d, origin, plane_normal);
+ }
+ else {
+ plane_normal[axis] = 1.0f;
+ /* if object, apply object rotation */
+ if (ob && (ob->type == OB_GPENCIL)) {
+ mul_mat3_m4_v3(ob->obmat, plane_normal);
+ }
}
- /* Compute theoretical optimal value using distances */
- bGPDspoint *pta, *ptc;
- int before = i - 1;
- int after = i + 1;
-
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
-
- pta = &gps->points[before];
- ptc = &gps->points[after];
+ /* Reproject the points in the plane */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
- /* the optimal value is the corresponding to the interpolation of the strength
- * at the distance of point b
- */
- const float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
- const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength;
+ /* get a vector from the point with the current view direction of the viewport */
+ ED_view3d_global_to_vector(rv3d, &pt->x, vn);
- /* Based on influence factor, blend between original and optimal */
- ptb->strength = (1.0f - inf) * ptb->strength + inf * optimal;
+ /* calculate line extreme point to create a ray that cross the plane */
+ mul_v3_fl(vn, -50.0f);
+ add_v3_v3v3(ray, &pt->x, vn);
- return true;
+ /* if the line never intersect, the point is not changed */
+ if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
+ copy_v3_v3(&pt->x, rpoint);
+ }
+ }
}
/**
-* Apply smooth for thickness to stroke point (use pressure)
-* \param gps Stroke to smooth
-* \param i Point index
-* \param inf Amount of smoothing to apply
-*/
-bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf)
+ * Reproject given point to a plane locked to axis to avoid stroke offset
+ * \param[in, out] pt : Point to affect
+ */
+void ED_gp_project_point_to_plane(Object *ob, RegionView3D *rv3d, const float origin[3], const int axis, bGPDspoint *pt)
{
- bGPDspoint *ptb = &gps->points[i];
-
- /* Do nothing if not enough points */
- if (gps->totpoints <= 2) {
- return false;
+ float plane_normal[3];
+ float vn[3];
+
+ float ray[3];
+ float rpoint[3];
+
+ /* normal vector for a plane locked to axis */
+ zero_v3(plane_normal);
+ if (axis < 0) {
+ /* if the axis is not locked, need a vector to the view direction
+ * in order to get the right size of the stroke.
+ */
+ ED_view3d_global_to_vector(rv3d, origin, plane_normal);
+ }
+ else {
+ plane_normal[axis] = 1.0f;
+ /* if object, apply object rotation */
+ if (ob && (ob->type == OB_GPENCIL)) {
+ mul_mat3_m4_v3(ob->obmat, plane_normal);
+ }
}
- /* Compute theoretical optimal value using distances */
- bGPDspoint *pta, *ptc;
- int before = i - 1;
- int after = i + 1;
-
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
-
- pta = &gps->points[before];
- ptc = &gps->points[after];
- /* the optimal value is the corresponding to the interpolation of the pressure
- * at the distance of point b
- */
- float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
- float optimal = (1.0f - fac) * pta->pressure + fac * ptc->pressure;
+ /* Reproject the points in the plane */
+ /* get a vector from the point with the current view direction of the viewport */
+ ED_view3d_global_to_vector(rv3d, &pt->x, vn);
- /* Based on influence factor, blend between original and optimal */
- ptb->pressure = (1.0f - inf) * ptb->pressure + inf * optimal;
+ /* calculate line extrem point to create a ray that cross the plane */
+ mul_v3_fl(vn, -50.0f);
+ add_v3_v3v3(ray, &pt->x, vn);
- return true;
+ /* if the line never intersect, the point is not changed */
+ if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
+ copy_v3_v3(&pt->x, rpoint);
+ }
}
+/* ******************************************************** */
+/* Stroke Operations */
+// XXX: Check if these functions duplicate stuff in blenkernel, and/or whether we should just deduplicate
+
/**
* Subdivide a stroke once, by adding a point half way between each pair of existing points
* \param gps Stroke data
- * \param new_totpoints Total number of points (after subdividing)
+ * \param subdivide Number of times to subdivide
*/
-void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints)
+void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide)
{
- /* Move points towards end of enlarged points array to leave space for new points */
- int y = 1;
- for (int i = gps->totpoints - 1; i > 0; i--) {
- gps->points[new_totpoints - y] = gps->points[i];
- y += 2;
- }
+ bGPDspoint *temp_points;
+ int totnewpoints, oldtotpoints;
+ int i2;
+
+ /* loop as many times as levels */
+ for (int s = 0; s < subdivide; s++) {
+ totnewpoints = gps->totpoints - 1;
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
+
+ /* resize the points arrys */
+ gps->totpoints += totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* move points from last to first to new place */
+ i2 = gps->totpoints - 1;
+ for (int i = oldtotpoints - 1; i > 0; i--) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *pt_final = &gps->points[i2];
+ MDeformVert *dvert = &gps->dvert[i];
+ MDeformVert *dvert_final = &gps->dvert[i2];
+
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+ pt_final->uv_fac = pt->uv_fac;
+ pt_final->uv_rot = pt->uv_rot;
+
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = dvert->dw;
+
+ i2 -= 2;
+ }
+ /* interpolate mid points */
+ i2 = 1;
+ for (int i = 0; i < oldtotpoints - 1; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i2];
+ MDeformVert *dvert_final = &gps->dvert[i2];
+
+ /* add a half way point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ 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);
+ 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);
+
+ dvert_final->totweight = 0;
+ dvert_final->dw = NULL;
+
+ i2 += 2;
+ }
- /* Create interpolated points */
- for (int i = 0; i < new_totpoints - 1; i += 2) {
- bGPDspoint *prev = &gps->points[i];
- bGPDspoint *pt = &gps->points[i + 1];
- bGPDspoint *next = &gps->points[i + 2];
+ MEM_SAFE_FREE(temp_points);
- /* Interpolate all values */
- interp_v3_v3v3(&pt->x, &prev->x, &next->x, 0.5f);
+ /* move points to smooth stroke */
+ /* duplicate points in a temp area with the new subdivide data */
+ temp_points = MEM_dupallocN(gps->points);
- pt->pressure = interpf(prev->pressure, next->pressure, 0.5f);
- pt->strength = interpf(prev->strength, next->strength, 0.5f);
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- pt->time = interpf(prev->time, next->time, 0.5f);
- }
+ /* extreme points are not changed */
+ for (int i = 0; i < gps->totpoints - 2; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i + 1];
- /* Update to new total number of points */
- gps->totpoints = new_totpoints;
+ /* move point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ }
+ /* free temp memory */
+ MEM_SAFE_FREE(temp_points);
+ }
}
/**
@@ -965,7 +1018,7 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints)
* \param gps Stroke data
* \param brush Brush data
*/
-void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush, RNG *rng)
+void gp_randomize_stroke(bGPDstroke *gps, Brush *brush, RNG *rng)
{
bGPDspoint *pt1, *pt2, *pt3;
float v1[3];
@@ -995,10 +1048,10 @@ void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush, RNG *rng)
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) {
+ 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->draw_random_sub / 10.0f);
+ 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) {
@@ -1011,31 +1064,46 @@ void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush, RNG *rng)
/* apply shift */
add_v3_v3(&pt->x, svec);
}
-
}
+
+/* ******************************************************** */
+/* Layer Parenting - Compute Parent Transforms */
+
/* calculate difference matrix */
-void ED_gpencil_parent_location(bGPDlayer *gpl, float diff_mat[4][4])
+void ED_gpencil_parent_location(
+ const Depsgraph *depsgraph, Object *obact, bGPdata *UNUSED(gpd),
+ bGPDlayer *gpl, float diff_mat[4][4])
{
- Object *ob = gpl->parent;
-
- if (ob == NULL) {
+ 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, ob->obmat, gpl->inverse);
+ mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse);
return;
}
else if (gpl->partype == PARBONE) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, gpl->parsubstr);
+ bPoseChannel *pchan = BKE_pose_channel_find_name(obparent_eval->pose, gpl->parsubstr);
if (pchan) {
float tmp_mat[4][4];
- mul_m4_m4m4(tmp_mat, ob->obmat, pchan->pose_mat);
+ mul_m4_m4m4(tmp_mat, obparent_eval->obmat, pchan->pose_mat);
mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse);
}
else {
- mul_m4_m4m4(diff_mat, ob->obmat, gpl->inverse); /* if bone not found use object (armature) */
+ mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); /* if bone not found use object (armature) */
}
return;
}
@@ -1046,7 +1114,7 @@ void ED_gpencil_parent_location(bGPDlayer *gpl, float diff_mat[4][4])
}
/* reset parent matrix for all layers */
-void ED_gpencil_reset_layers_parent(bGPdata *gpd)
+void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd)
{
bGPDspoint *pt;
int i;
@@ -1071,7 +1139,7 @@ void ED_gpencil_reset_layers_parent(bGPdata *gpd)
/* only redo if any change */
if (!equals_m4m4(gpl->inverse, cur_mat)) {
/* first apply current transformation to all strokes */
- ED_gpencil_parent_location(gpl, diff_mat);
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
@@ -1086,90 +1154,580 @@ void ED_gpencil_reset_layers_parent(bGPdata *gpd)
}
}
/* ******************************************************** */
-bool ED_gpencil_stroke_minmax(
- const bGPDstroke *gps, const bool use_select,
- float r_min[3], float r_max[3])
+/* GP Object Stuff */
+
+/* Helper function to create new OB_GPENCIL Object */
+Object *ED_add_gpencil_object(bContext *C, Scene *scene, const float loc[3])
{
- const bGPDspoint *pt;
- int i;
- bool changed = false;
+ float rot[3] = {0.0f};
+
+ Object *ob = ED_object_add_type(C, OB_GPENCIL, NULL, loc, rot, false, scene->lay);
+
+ /* define size */
+ BKE_object_obdata_size_init(ob, GP_OBGPENCIL_DEFAULT_SIZE);
+ /* create default brushes and colors */
+ ED_gpencil_add_defaults(C);
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {;
- minmax_v3v3_v3(r_min, r_max, &pt->x);
- changed = true;
+ return ob;
+}
+
+/* Helper function to create default colors and drawing brushes */
+void ED_gpencil_add_defaults(bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ /* first try to reuse default material */
+ if (ob->actcol > 0) {
+ Material *ma = give_current_material(ob, ob->actcol);
+ if ((ma) && (ma->gp_style == NULL)) {
+ BKE_material_init_gpencil_settings(ma);
}
}
- return changed;
+
+ /* ensure color exist */
+ BKE_gpencil_material_ensure(bmain, ob);
+
+ Paint *paint = BKE_brush_get_gpencil_paint(ts);
+ /* if not exist, create a new one */
+ if (paint->brush == NULL) {
+ /* create new brushes */
+ BKE_brush_gpencil_presets(C);
+ }
+
}
-/* Dynamic Enums of GP Brushes */
-const EnumPropertyItem *ED_gpencil_brushes_enum_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
- bool *r_free)
+/* ******************************************************** */
+/* Vertex Groups */
+
+/* assign points to vertex group */
+void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- bGPDbrush *brush;
- EnumPropertyItem *item = NULL, item_tmp = { 0 };
- int totitem = 0;
- int i = 0;
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return;
- if (ELEM(NULL, C, ts)) {
- return DummyRNA_DEFAULT_items;
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+ if (pt->flag & GP_SPOINT_SELECT) {
+ BKE_gpencil_vgroup_add_point_weight(dvert, def_nr, weight);
+ }
+ }
+ }
}
+ CTX_DATA_END;
+}
- /* Existing brushes */
- for (brush = ts->gp_brushes.first; brush; brush = brush->next, i++) {
- item_tmp.identifier = brush->info;
- item_tmp.name = brush->info;
- item_tmp.value = i;
+/* remove points from vertex group */
+void ED_gpencil_vgroup_remove(bContext *C, Object *ob)
+{
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return;
- if (brush->flag & GP_BRUSH_ACTIVE)
- item_tmp.icon = ICON_BRUSH_DATA;
- else
- item_tmp.icon = ICON_NONE;
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
- RNA_enum_item_add(&item, &totitem, &item_tmp);
+ if ((pt->flag & GP_SPOINT_SELECT) && (dvert->totweight > 0)) {
+ BKE_gpencil_vgroup_remove_point_weight(dvert, def_nr);
+ }
+ }
}
+ CTX_DATA_END;
+}
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
+/* select points of vertex group */
+void ED_gpencil_vgroup_select(bContext *C, Object *ob)
+{
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return;
- return item;
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ if (BKE_gpencil_vgroup_use_index(dvert, def_nr) > -1.0f) {
+ pt->flag |= GP_SPOINT_SELECT;
+ gps->flag |= GP_STROKE_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
}
-/* Dynamic Enums of GP Palettes */
-const EnumPropertyItem *ED_gpencil_palettes_enum_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
- bool *r_free)
+/* unselect points of vertex group */
+void ED_gpencil_vgroup_deselect(bContext *C, Object *ob)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- bGPDpalette *palette;
- EnumPropertyItem *item = NULL, item_tmp = { 0 };
- int totitem = 0;
- int i = 0;
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return;
- if (ELEM(NULL, C, gpd)) {
- return DummyRNA_DEFAULT_items;
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ if (BKE_gpencil_vgroup_use_index(dvert, def_nr) > -1.0f) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ gps->flag |= GP_STROKE_SELECT;
+ }
+ }
}
+ CTX_DATA_END;
+}
- /* Existing palettes */
- for (palette = gpd->palettes.first; palette; palette = palette->next, i++) {
- item_tmp.identifier = palette->info;
- item_tmp.name = palette->info;
- item_tmp.value = i;
+/* ******************************************************** */
+/* Cursor drawing */
- if (palette->flag & PL_PALETTE_ACTIVE)
- item_tmp.icon = ICON_COLOR;
- else
- item_tmp.icon = ICON_NONE;
+/* check if cursor is in drawing region */
+static bool gp_check_cursor_region(bContext *C, int mval[2])
+{
+ ARegion *ar = CTX_wm_region(C);
+ ScrArea *sa = CTX_wm_area(C);
+ /* TODO: add more spacetypes */
+ if (!ELEM(sa->spacetype, SPACE_VIEW3D)) {
+ return false;
+ }
+ if ((ar) && (ar->regiontype != RGN_TYPE_WINDOW)) {
+ return false;
+ }
+ else if (ar) {
+ rcti region_rect;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
+ /* Perform bounds check using */
+ ED_region_visible_rect(ar, &region_rect);
+ return BLI_rcti_isect_pt_v(&region_rect, mval);
+ }
+ else {
+ return false;
}
+}
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
+/* draw eraser cursor */
+void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y)
+{
+ short radius = (short)brush->size;
- return item;
+ GPUVertFormat *format = immVertexFormat();
+ const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ immUniformColor4ub(255, 100, 100, 20);
+ imm_draw_circle_fill_2d(shdr_pos, x, y, radius, 40);
+
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniform1f("dash_width", 12.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ imm_draw_circle_wire_2d(shdr_pos, x, y, radius,
+ /* XXX Dashed shader gives bad results with sets of small segments currently,
+ * temp hack around the issue. :( */
+ max_ii(8, radius / 2)); /* was fixed 40 */
+
+ immUnbindProgram();
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+}
+
+/* Helper callback for drawing the cursor itself */
+static void gp_brush_drawcursor(bContext *C, int x, int y, void *customdata)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ GP_EditBrush_Data *brush = NULL;
+ Brush *paintbrush = NULL;
+ Material *ma = NULL;
+ MaterialGPencilStyle *gp_style = NULL;
+ int *last_mouse_position = customdata;
+
+ if ((gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE)) {
+ brush = &gset->brush[gset->weighttype];
+ }
+ else {
+ brush = &gset->brush[gset->brushtype];
+ }
+
+ /* default radius and color */
+ float color[3] = {1.0f, 1.0f, 1.0f};
+ float darkcolor[3];
+ float radius = 3.0f;
+
+ int mval[2] = {x, y};
+ /* check if cursor is in drawing region and has valid datablock */
+ if ((!gp_check_cursor_region(C, mval)) || (gpd == NULL)) {
+ return;
+ }
+
+ /* for paint use paint brush size and color */
+ if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
+ paintbrush = BKE_brush_getactive_gpencil(scene->toolsettings);
+ /* while drawing hide */
+ if ((gpd->runtime.sbuffer_size > 0) &&
+ (paintbrush) && ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
+ ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0))
+ {
+ return;
+ }
+
+ if (paintbrush) {
+ if ((paintbrush->gpencil_settings->flag & GP_BRUSH_ENABLE_CURSOR) == 0) {
+ return;
+ }
+
+ /* eraser has special shape and use a different shader program */
+ if (paintbrush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE) {
+ ED_gpencil_brush_draw_eraser(paintbrush, x, y);
+ return;
+ }
+
+ /* get current drawing color */
+ ma = BKE_gpencil_get_material_from_brush(paintbrush);
+ if (ma == NULL) {
+ BKE_gpencil_material_ensure(bmain, ob);
+ /* assign the first material to the brush */
+ ma = give_current_material(ob, 1);
+ paintbrush->gpencil_settings->material = ma;
+ }
+ gp_style = ma->gp_style;
+
+ /* after some testing, display the size of the brush is not practical because
+ * is too disruptive and the size of cursor does not change with zoom factor.
+ * The decision was to use a fix size, instead of paintbrush->thickness value.
+ */
+ if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
+ ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
+ ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
+ (paintbrush->gpencil_settings->brush_type == GP_BRUSH_TYPE_DRAW))
+ {
+ radius = 2.0f;
+ copy_v3_v3(color, gp_style->stroke_rgba);
+ }
+ else {
+ radius = 5.0f;
+ copy_v3_v3(color, paintbrush->add_col);
+ }
+ }
+ else {
+ return;
+ }
+ }
+
+ /* for sculpt use sculpt brush size */
+ if (GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd)) {
+ if (brush) {
+ if ((brush->flag & GP_EDITBRUSH_FLAG_ENABLE_CURSOR) == 0) {
+ return;
+ }
+
+ radius = brush->size;
+ if (brush->flag & (GP_EDITBRUSH_FLAG_INVERT | GP_EDITBRUSH_FLAG_TMP_INVERT)) {
+ copy_v3_v3(color, brush->curcolor_sub);
+ }
+ else {
+ copy_v3_v3(color, brush->curcolor_add);
+ }
+ }
+ }
+
+ /* draw icon */
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+
+ /* Inner Ring: Color from UI panel */
+ immUniformColor4f(color[0], color[1], color[2], 0.8f);
+ if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
+ ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
+ ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
+ (paintbrush->gpencil_settings->brush_type == GP_BRUSH_TYPE_DRAW))
+ {
+ imm_draw_circle_fill_2d(pos, x, y, radius, 40);
+ }
+ else {
+ imm_draw_circle_wire_2d(pos, x, y, radius, 40);
+ }
+
+ /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
+ mul_v3_v3fl(darkcolor, color, 0.40f);
+ immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f);
+ imm_draw_circle_wire_2d(pos, x, y, radius + 1, 40);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+
+ /* Draw line for lazy mouse */
+ if ((last_mouse_position) &&
+ (paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP))
+ {
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+
+ copy_v3_v3(color, paintbrush->add_col);
+ immUniformColor4f(color[0], color[1], color[2], 0.8f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, x, y);
+ immVertex2f(pos, last_mouse_position[0] + ar->winrct.xmin,
+ last_mouse_position[1] + ar->winrct.ymin);
+ immEnd();
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+ }
+
+ immUnbindProgram();
+}
+
+/* Turn brush cursor in on/off */
+void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
+{
+ Scene *scene = CTX_data_scene(C);
+ GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt;
+ int *lastpost = customdata;
+
+ if (gset->paintcursor && !enable) {
+ /* clear cursor */
+ WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
+ gset->paintcursor = NULL;
+ }
+ else if (enable) {
+ /* in some situations cursor could be duplicated, so it is better disable first if exist */
+ if (gset->paintcursor) {
+ /* clear cursor */
+ WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
+ gset->paintcursor = NULL;
+ }
+ /* enable cursor */
+ gset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ NULL,
+ gp_brush_drawcursor,
+ (lastpost) ? customdata : NULL);
+ }
+}
+
+/* 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_BrushEdit_Settings *gset = &ts->gp_sculpt;
+
+ switch (newmode) {
+ case OB_MODE_GPENCIL_SCULPT:
+ gset->flag &= ~GP_BRUSHEDIT_FLAG_WEIGHT_MODE;
+ if ((gset->brushtype < 0) || (gset->brushtype >= GP_EDITBRUSH_TYPE_WEIGHT)) {
+ gset->brushtype = GP_EDITBRUSH_TYPE_PUSH;
+ }
+ break;
+ case OB_MODE_GPENCIL_WEIGHT:
+ gset->flag |= GP_BRUSHEDIT_FLAG_WEIGHT_MODE;
+ if ((gset->weighttype < GP_EDITBRUSH_TYPE_WEIGHT) || (gset->weighttype >= TOT_GP_EDITBRUSH_TYPES)) {
+ gset->weighttype = GP_EDITBRUSH_TYPE_WEIGHT;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/* set object modes */
+void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
+{
+ if (!gpd) {
+ return;
+ }
+
+ switch (newmode) {
+ case OB_MODE_GPENCIL_EDIT:
+ gpd->flag |= GP_DATA_STROKE_EDITMODE;
+ gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ break;
+ case OB_MODE_GPENCIL_PAINT:
+ gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ gpd->flag |= GP_DATA_STROKE_PAINTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ break;
+ case OB_MODE_GPENCIL_SCULPT:
+ gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ 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_GPENCIL_SCULPT);
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ break;
+ case OB_MODE_GPENCIL_WEIGHT:
+ gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ 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_GPENCIL_WEIGHT);
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ break;
+ default:
+ gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ break;
+ }
+}
+
+/* helper to convert 2d to 3d for simple drawing buffer */
+static void gpencil_stroke_convertcoords(ARegion *ar, const tGPspoint *point2D, float origin[3], float out[3])
+{
+ float mval_f[2] = { (float)point2D->x, (float)point2D->y };
+ float mval_prj[2];
+ float rvec[3], dvec[3];
+ float zfac;
+
+ copy_v3_v3(rvec, origin);
+
+ zfac = ED_view3d_calc_zfac(ar->regiondata, rvec, NULL);
+
+ if (ED_view3d_project_float_global(ar, 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(ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(out, rvec, dvec);
+ }
+ else {
+ zero_v3(out);
+ }
+}
+
+/* convert 2d tGPspoint to 3d bGPDspoint */
+void ED_gpencil_tpoint_to_point(ARegion *ar, float origin[3], const tGPspoint *tpt, bGPDspoint *pt)
+{
+ float p3d[3];
+ /* conversion to 3d format */
+ gpencil_stroke_convertcoords(ar, tpt, origin, p3d);
+ copy_v3_v3(&pt->x, p3d);
+
+ pt->pressure = tpt->pressure;
+ pt->strength = tpt->strength;
+ pt->uv_fac = tpt->uv_fac;
+ 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_material_gpencil_settings_get(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.000100f;
+ }
+ pixsize = MAX2(pixsize, 0.0000001f);
+
+ bGPDspoint *pt = NULL;
+ bGPDspoint *ptb = NULL;
+ int i;
+ float totlen = 0;
+
+ /* 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->sima)) {
+ factor = gp_style->sima->gen_x;
+ }
+ 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)
+{
+ Material *gps_ma = NULL;
+ /* read all strokes */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = ob->data;
+ if (gpd == NULL) {
+ continue;
+ }
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* 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) {
+ /* check if it is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+ gps_ma = give_current_material(ob, gps->mat_nr + 1);
+ /* update */
+ if ((gps_ma) && (gps_ma == mat)) {
+ ED_gpencil_calc_stroke_uv(ob, gps);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
/* ******************************************************** */
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 59a54f03e56..ae86e4a5fbf 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -197,6 +197,8 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_NLATRACK,
ANIMTYPE_NLAACTION,
+ ANIMTYPE_PALETTE,
+
/* always as last item, the total number of channel types... */
ANIMTYPE_NUM_TYPES
} eAnim_ChannelType;
@@ -347,6 +349,9 @@ typedef enum eAnimFilter_Flags {
/* Movie clip only */
#define EXPANDED_MCLIP(clip) (clip->flag & MCLIP_DATA_EXPAND)
+/* Palette only */
+#define EXPANDED_PALETTE(palette) (palette->flag & PALETTE_DATA_EXPAND)
+
/* AnimData - NLA mostly... */
#define SEL_ANIMDATA(adt) (adt->flag & ADT_UI_SELECTED)
diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h
index 7d509d1243a..333e3d72615 100644
--- a/source/blender/editors/include/ED_datafiles.h
+++ b/source/blender/editors/include/ED_datafiles.h
@@ -42,6 +42,9 @@ extern char datatoc_preview_blend[];
extern int datatoc_preview_cycles_blend_size;
extern char datatoc_preview_cycles_blend[];
+extern int datatoc_preview_grease_pencil_blend_size;
+extern char datatoc_preview_grease_pencil_blend[];
+
extern int datatoc_blender_icons16_png_size;
extern char datatoc_blender_icons16_png[];
@@ -239,6 +242,66 @@ extern char datatoc_mc23_jpg[];
extern int datatoc_mc24_jpg_size;
extern char datatoc_mc24_jpg[];
+/* grease pencil sculpt brushes files */
+
+extern int datatoc_gp_brush_smooth_png_size;
+extern char datatoc_gp_brush_smooth_png[];
+
+extern int datatoc_gp_brush_thickness_png_size;
+extern char datatoc_gp_brush_thickness_png[];
+
+extern int datatoc_gp_brush_strength_png_size;
+extern char datatoc_gp_brush_strength_png[];
+
+extern int datatoc_gp_brush_grab_png_size;
+extern char datatoc_gp_brush_grab_png[];
+
+extern int datatoc_gp_brush_push_png_size;
+extern char datatoc_gp_brush_push_png[];
+
+extern int datatoc_gp_brush_twist_png_size;
+extern char datatoc_gp_brush_twist_png[];
+
+extern int datatoc_gp_brush_pinch_png_size;
+extern char datatoc_gp_brush_pinch_png[];
+
+extern int datatoc_gp_brush_randomize_png_size;
+extern char datatoc_gp_brush_randomize_png[];
+
+extern int datatoc_gp_brush_clone_png_size;
+extern char datatoc_gp_brush_clone_png[];
+
+extern int datatoc_gp_brush_weight_png_size;
+extern char datatoc_gp_brush_weight_png[];
+
+extern int datatoc_gp_brush_pencil_png_size;
+extern char datatoc_gp_brush_pencil_png[];
+
+extern int datatoc_gp_brush_pen_png_size;
+extern char datatoc_gp_brush_pen_png[];
+
+extern int datatoc_gp_brush_ink_png_size;
+extern char datatoc_gp_brush_ink_png[];
+
+extern int datatoc_gp_brush_inknoise_png_size;
+extern char datatoc_gp_brush_inknoise_png[];
+
+extern int datatoc_gp_brush_block_png_size;
+extern char datatoc_gp_brush_block_png[];
+
+extern int datatoc_gp_brush_marker_png_size;
+extern char datatoc_gp_brush_marker_png[];
+
+extern int datatoc_gp_brush_fill_png_size;
+extern char datatoc_gp_brush_fill_png[];
+
+extern int datatoc_gp_brush_erase_soft_png_size;
+extern char datatoc_gp_brush_erase_soft_png[];
+
+extern int datatoc_gp_brush_erase_hard_png_size;
+extern char datatoc_gp_brush_erase_hard_png[];
+extern int datatoc_gp_brush_erase_stroke_png_size;
+extern char datatoc_gp_brush_erase_stroke_png[];
#endif /* __ED_DATAFILES_H__ */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index f1f2ce29e7f..3013b455de4 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -30,64 +30,44 @@
#ifndef __ED_GPENCIL_H__
#define __ED_GPENCIL_H__
-#include "ED_numinput.h"
-
struct ID;
struct ListBase;
-struct bContext;
-struct Depsgraph;
-struct ScrArea;
-struct ARegion;
-struct View3D;
-struct Object;
+struct PointerRNA;
+struct rcti;
+
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
-struct bGPDpalette;
-struct bGPDpalettecolor;
-struct bAnimContext;
-struct KeyframeEditData;
-struct PointerRNA;
+struct bGPDspoint;
+struct Brush;
+
+struct Main;
+struct bContext;
+struct EvaluationContext;
+struct Depsgraph;
+struct ScrArea;
+struct ARegion;
+struct RegionView3D;
struct Scene;
+struct ToolSettings;
struct ViewLayer;
-struct wmWindowManager;
-struct wmKeyConfig;
-
-
-/* ------------- Grease-Pencil Helpers ---------------- */
-typedef struct tGPDinterpolate_layer {
- struct tGPDinterpolate_layer *next, *prev;
-
- struct bGPDlayer *gpl; /* layer */
- struct bGPDframe *prevFrame; /* frame before current frame (interpolate-from) */
- struct bGPDframe *nextFrame; /* frame after current frame (interpolate-to) */
- struct bGPDframe *interFrame; /* interpolated frame */
- float factor; /* interpolate factor */
+struct View3D;
-} tGPDinterpolate_layer;
+struct Object;
+struct Material;
-/* Temporary interpolate operation data */
-typedef struct tGPDinterpolate {
- struct Scene *scene; /* current scene from context */
- struct ScrArea *sa; /* area where painting originated */
- struct ARegion *ar; /* region where painting originated */
- struct bGPdata *gpd; /* current GP datablock */
+struct bAnimContext;
+struct KeyframeEditData;
- int cframe; /* current frame number */
- ListBase ilayers; /* (tGPDinterpolate_layer) layers to be interpolated */
- float shift; /* value for determining the displacement influence */
- float init_factor; /* initial interpolation factor for active layer */
- float low_limit; /* shift low limit (-100%) */
- float high_limit; /* shift upper limit (200%) */
- int flag; /* flag from toolsettings */
+struct wmKeyConfig;
+struct wmOperator;
+struct wmWindow;
+struct wmWindowManager;
- NumInput num; /* numeric input */
- void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */
- void *draw_handle_screen; /* handle for drawing strokes while operator is running screen stuff */
-} tGPDinterpolate;
+/* ------------- Grease-Pencil Runtime Data ---------------- */
-/* Temporary 'Stroke Point' data
+/* Temporary 'Stroke Point' data (2D / screen-space)
*
* Used as part of the 'stroke cache' used during drawing of new strokes
*/
@@ -96,27 +76,43 @@ typedef struct tGPspoint {
float pressure; /* pressure of tablet at this point */
float strength; /* pressure of tablet at this point for alpha factor */
float time; /* Time relative to stroke start (used when converting to path) */
+ float uv_fac; /* factor of uv along the stroke */
+ float uv_rot; /* uv rotation for dor mode */
} tGPspoint;
-
-/* Check if 'sketching sessions' are enabled */
-#define GPENCIL_SKETCH_SESSIONS_ON(scene) ((scene)->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINTSESSIONS_ON)
+/* 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 */
-struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *ptr);
+struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *r_ptr);
+
struct bGPdata *ED_gpencil_data_get_active(const struct bContext *C);
+struct bGPdata *ED_gpencil_data_get_active_evaluated(const struct bContext *C);
/* Context independent (i.e. each required part is passed in instead) */
-struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ID *screen_id, struct Scene *scene,
- struct ScrArea *sa, struct Object *ob,
- struct PointerRNA *ptr);
-struct bGPdata *ED_gpencil_data_get_active_direct(struct ID *screen_id, struct Scene *scene,
- struct ScrArea *sa, struct Object *ob);
+struct bGPdata **ED_gpencil_data_get_pointers_direct(
+ struct ID *screen_id,
+ struct ScrArea *sa,
+ struct Scene *scene,
+ struct Object *ob,
+ struct PointerRNA *r_ptr);
+struct bGPdata *ED_gpencil_data_get_active_direct(
+ struct ID *screen_id,
+ struct ScrArea *sa,
+ struct Scene *scene,
+ struct Object *ob);
+
+bool ED_gpencil_data_owner_is_annotation(struct PointerRNA *owner_ptr);
/* 3D View */
-struct bGPdata *ED_gpencil_data_get_active_v3d(struct Scene *scene, struct ViewLayer *view_layer);
+struct bGPdata *ED_gpencil_data_get_active_v3d(struct ViewLayer *view_layer);
bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfra);
@@ -124,13 +120,7 @@ bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfr
bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *sa, const struct bGPDstroke *gps);
bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps);
-bool ED_gpencil_stroke_color_use(const struct bGPDlayer *gpl, const struct bGPDstroke *gps);
-
-struct bGPDpalettecolor *ED_gpencil_stroke_getcolor(struct bGPdata *gpd, struct bGPDstroke *gps);
-
-bool ED_gpencil_stroke_minmax(
- const struct bGPDstroke *gps, const bool use_select,
- float r_min[3], float r_max[3]);
+bool ED_gpencil_stroke_color_use(struct Object *ob, const struct bGPDlayer *gpl, const struct bGPDstroke *gps);
/* ----------- Grease Pencil Operators ----------------- */
@@ -150,16 +140,29 @@ void ED_gpencil_strokes_copybuf_free(void);
void ED_gpencil_draw_2dimage(const struct bContext *C);
void ED_gpencil_draw_view2d(const struct bContext *C, bool onlyv2d);
-void ED_gpencil_draw_view3d(struct wmWindowManager *wm,
- struct Scene *scene,
- struct ViewLayer *view_layer,
- struct Depsgraph *depsgraph,
- struct View3D *v3d,
- struct ARegion *ar,
- bool only3d);
-void ED_gpencil_draw_ex(struct Scene *scene, struct bGPdata *gpd, int winx, int winy,
- const int cfra, const char spacetype);
-void ED_gp_draw_interpolation(struct tGPDinterpolate *tgpi, const int type);
+void ED_gpencil_draw_view3d(
+ struct wmWindowManager *wm,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct Depsgraph *depsgraph,
+ struct View3D *v3d,
+ struct ARegion *ar,
+ bool only3d);
+void ED_gpencil_draw_view3d_annotations(
+ struct Scene *scene, struct Depsgraph *depsgraph,
+ struct View3D *v3d, struct ARegion *ar,
+ bool only3d);
+void ED_gpencil_draw_view3d_object(
+ struct wmWindowManager *wm,
+ struct Scene *scene,
+ struct Depsgraph *depsgraph,
+ struct Object *ob,
+ struct View3D *v3d,
+ struct ARegion *ar,
+ bool only3d);
+void ED_gpencil_draw_ex(
+ struct RegionView3D *rv3d, struct Scene *scene, struct bGPdata *gpd, int winx, int winy,
+ const int cfra, const char spacetype);
/* ----------- Grease-Pencil AnimEdit API ------------------ */
bool ED_gplayer_frames_looper(struct bGPDlayer *gpl, struct Scene *scene,
@@ -192,10 +195,45 @@ int ED_undo_gpencil_step(struct bContext *C, int step, const char *name);
/* ------------ Transformation Utilities ------------ */
-/* get difference matrix using parent */
-void ED_gpencil_parent_location(struct bGPDlayer *gpl, float diff_mat[4][4]);
+/* 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 bGPdata *gpd);
+void ED_gpencil_reset_layers_parent(struct Depsgraph *depsgraph, struct Object *obact, struct bGPdata *gpd);
+
+/* cursor utilities */
+void ED_gpencil_brush_draw_eraser(struct Brush *brush, int x, int y);
+
+/* ----------- Add Primitive Utilities -------------- */
+
+void ED_gpencil_create_monkey(struct bContext *C, float mat[4][4]);
+
+/* ------------ Object Utilities ------------ */
+struct Object *ED_add_gpencil_object(struct bContext *C, struct Scene *scene, const float loc[3]);
+void ED_gpencil_add_defaults(struct bContext *C);
+/* set object modes */
+void ED_gpencil_setup_modes(struct bContext *C, struct bGPdata *gpd, int newmode);
+
+void ED_gp_project_stroke_to_plane(struct Object *ob, struct RegionView3D *rv3d, struct bGPDstroke *gps, const float origin[3], const int axis);
+void ED_gp_project_point_to_plane(struct Object *ob, struct RegionView3D *rv3d, const float origin[3], const int axis, struct bGPDspoint *pt);
+void ED_gp_get_drawing_reference(struct View3D *v3d, struct Scene *scene, struct Object *ob, struct bGPDlayer *gpl, char align_flag, float vec[3]);
+
+/* set sculpt cursor */
+void ED_gpencil_toggle_brush_cursor(struct bContext *C, bool enable, void *customdata);
+
+/* vertex groups */
+void ED_gpencil_vgroup_assign(struct bContext *C, struct Object *ob, float weight);
+void ED_gpencil_vgroup_remove(struct bContext *C, struct Object *ob);
+void ED_gpencil_vgroup_select(struct bContext *C, struct Object *ob);
+void ED_gpencil_vgroup_deselect(struct bContext *C, struct Object *ob);
+
+/* join objects */
+int ED_gpencil_join_objects_exec(struct bContext *C, struct wmOperator *op);
+/* texture coordinate utilities */
+void ED_gpencil_tpoint_to_point(struct ARegion *ar, 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);
#endif /* __ED_GPENCIL_H__ */
diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h
index 64dee410526..45a0680e0c1 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -42,6 +42,7 @@ struct bActionGroup;
struct Object;
struct ListBase;
struct bGPDlayer;
+struct Palette;
struct MaskLayer;
struct Scene;
struct View2D;
@@ -151,9 +152,11 @@ void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tr
/* DopeSheet Summary */
void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
/* Grease Pencil datablock summary */
-void gpencil_to_keylist(struct bDopeSheet *ads, struct bGPdata *gpd, struct DLRBT_Tree *keys);
+void gpencil_to_keylist(struct bDopeSheet *ads, struct bGPdata *gpd, struct DLRBT_Tree *keys, const bool active);
/* Grease Pencil Layer */
void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys);
+/* Palette */
+void palette_to_keylist(struct bDopeSheet *ads, struct Palette *palette, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
/* Mask */
void mask_to_keylist(struct bDopeSheet *UNUSED(ads), struct MaskLayer *masklay, struct DLRBT_Tree *keys);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 9fd5cc99073..a39523983ba 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -42,6 +42,7 @@ struct ID;
struct Main;
struct Menu;
struct ModifierData;
+struct ShaderFxData;
struct Object;
struct ReportList;
struct Scene;
@@ -261,6 +262,40 @@ bool ED_object_iter_other(
bool ED_object_multires_update_totlevels_cb(struct Object *ob, void *totlevel_v);
+
+/* object_greasepencil_modifier.c */
+struct GpencilModifierData *ED_object_gpencil_modifier_add(
+ struct ReportList *reports, struct Main *bmain, struct Scene *scene,
+ struct Object *ob, const char *name, int type);
+bool ED_object_gpencil_modifier_remove(
+ struct ReportList *reports, struct Main *bmain,
+ struct Object *ob, struct GpencilModifierData *md);
+void ED_object_gpencil_modifier_clear(
+ struct Main *bmain, struct Object *ob);
+int ED_object_gpencil_modifier_move_down(
+ struct ReportList *reports, struct Object *ob, struct GpencilModifierData *md);
+int ED_object_gpencil_modifier_move_up(
+ struct ReportList *reports, struct Object *ob, struct GpencilModifierData *md);
+int ED_object_gpencil_modifier_apply(
+ struct Main *bmain, struct ReportList *reports, struct Depsgraph *depsgraph,
+ struct Object *ob, struct GpencilModifierData *md, int mode);
+int ED_object_gpencil_modifier_copy(
+ struct ReportList *reports, struct Object *ob, struct GpencilModifierData *md);
+
+/* object_shader_fx.c */
+struct ShaderFxData *ED_object_shaderfx_add(
+ struct ReportList *reports, struct Main *bmain, struct Scene *scene,
+ struct Object *ob, const char *name, int type);
+bool ED_object_shaderfx_remove(
+ struct ReportList *reports, struct Main *bmain,
+ struct Object *ob, struct ShaderFxData *fx);
+void ED_object_shaderfx_clear(
+ struct Main *bmain, struct Object *ob);
+int ED_object_shaderfx_move_down(
+ struct ReportList *reports, struct Object *ob, struct ShaderFxData *fx);
+int ED_object_shaderfx_move_up(
+ struct ReportList *reports, struct Object *ob, struct ShaderFxData *fx);
+
/* object_select.c */
void ED_object_select_linked_by_id(struct bContext *C, struct ID *id);
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index ec4c7dddd4c..dec02faf85c 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -1001,6 +1001,30 @@ DEF_ICON(MATCAP_22)
DEF_ICON(MATCAP_23)
DEF_ICON(MATCAP_24)
+/* grease pencil sculpt */
+DEF_ICON(GPBRUSH_SMOOTH)
+DEF_ICON(GPBRUSH_THICKNESS)
+DEF_ICON(GPBRUSH_STRENGTH)
+DEF_ICON(GPBRUSH_GRAB)
+DEF_ICON(GPBRUSH_PUSH)
+DEF_ICON(GPBRUSH_TWIST)
+DEF_ICON(GPBRUSH_PINCH)
+DEF_ICON(GPBRUSH_RANDOMIZE)
+DEF_ICON(GPBRUSH_CLONE)
+DEF_ICON(GPBRUSH_WEIGHT)
+
+DEF_ICON(GPBRUSH_PENCIL)
+DEF_ICON(GPBRUSH_PEN)
+DEF_ICON(GPBRUSH_INK)
+DEF_ICON(GPBRUSH_INKNOISE)
+DEF_ICON(GPBRUSH_BLOCK)
+DEF_ICON(GPBRUSH_MARKER)
+DEF_ICON(GPBRUSH_CUSTOM)
+DEF_ICON(GPBRUSH_FILL)
+DEF_ICON(GPBRUSH_ERASE_SOFT)
+DEF_ICON(GPBRUSH_ERASE_HARD)
+DEF_ICON(GPBRUSH_ERASE_STROKE)
+
/* vector icons, VICO_ prefix added */
DEF_VICO(SMALL_TRI_RIGHT_VEC)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index b4756eaed0f..fc3dd3f9968 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1022,7 +1022,8 @@ uiLayout *uiLayoutRadial(uiLayout *layout);
void uiTemplateHeader(uiLayout *layout, struct bContext *C);
void uiTemplateID(
uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
- const char *newop, const char *openop, const char *unlinkop, int filter);
+ const char *newop, const char *openop, const char *unlinkop,
+ int filter, const bool live_icon);
void uiTemplateIDBrowse(
uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
const char *newop, const char *openop, const char *unlinkop, int filter);
@@ -1052,6 +1053,12 @@ void uiTemplatePathBuilder(
uiLayout *layout, struct PointerRNA *ptr, const char *propname,
struct PointerRNA *root_ptr, const char *text);
uiLayout *uiTemplateModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
+uiLayout *uiTemplateGpencilModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
+void uiTemplateGpencilColorPreview(
+ uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
+ int rows, int cols, float scale, int filter);
+
+uiLayout *uiTemplateShaderFx(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
void uiTemplateOperatorRedoProperties(uiLayout *layout, const struct bContext *C);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 7255640bedc..4f77b797ec0 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -47,6 +47,7 @@
#include "DNA_brush_types.h"
#include "DNA_curve_types.h"
#include "DNA_dynamicpaint_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -109,6 +110,7 @@ typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha);
#define ICON_TYPE_VECTOR 4
#define ICON_TYPE_GEOM 5
#define ICON_TYPE_EVENT 6 /* draw keymap entries using custom renderer. */
+#define ICON_TYPE_GPLAYER 7
typedef struct DrawInfo {
int type;
@@ -391,6 +393,28 @@ DEF_VICON_COLORSET_DRAW_NTH(20, 19)
#undef DEF_VICON_COLORSET_DRAW_NTH
+/* Dynamically render icon instead of rendering a plain color to a texture/buffer
+ * This is mot strictly a "vicon", as it needs access to icon->obj to get the color info,
+ * but it works in a very similar way.
+ */
+static void vicon_gplayer_color_draw(Icon *icon, int x, int y, int w, int h)
+{
+ bGPDlayer *gpl = (bGPDlayer *)icon->obj;
+
+ /* Just draw a colored rect - Like for vicon_colorset_draw() */
+ /* TODO: Make this have rounded corners, and maybe be a bit smaller.
+ * However, UI_draw_roundbox_aa() draws the colors too dark, so can't be used.
+ */
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3fv(gpl->color);
+ immRecti(pos, x, y, x + w - 1, y + h - 1);
+
+ immUnbindProgram();
+}
+
+
#ifndef WITH_HEADLESS
static void init_brush_icons(void)
@@ -443,6 +467,30 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_BRUSH_ROTATE, twist);
INIT_BRUSH_ICON(ICON_BRUSH_VERTEXDRAW, vertexdraw);
+ /* grease pencil sculpt */
+ INIT_BRUSH_ICON(ICON_GPBRUSH_SMOOTH, gp_brush_smooth);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_THICKNESS, gp_brush_thickness);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_STRENGTH, gp_brush_strength);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_GRAB, gp_brush_grab);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_PUSH, gp_brush_push);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_TWIST, gp_brush_twist);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_PINCH, gp_brush_pinch);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_RANDOMIZE, gp_brush_randomize);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_CLONE, gp_brush_clone);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_WEIGHT, gp_brush_weight);
+
+ /* grease pencil drawing brushes */
+ INIT_BRUSH_ICON(ICON_GPBRUSH_PENCIL, gp_brush_pencil);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_PEN, gp_brush_pen);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_INK, gp_brush_ink);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_INKNOISE, gp_brush_inknoise);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_BLOCK, gp_brush_block);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_MARKER, gp_brush_marker);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_FILL, gp_brush_fill);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_SOFT, gp_brush_erase_soft);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_HARD, gp_brush_erase_hard);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_STROKE, gp_brush_erase_stroke);
+
#undef INIT_BRUSH_ICON
}
@@ -877,6 +925,9 @@ static DrawInfo *icon_create_drawinfo(Icon *icon)
else if (icon_data_type == ICON_DATA_STUDIOLIGHT) {
di->type = ICON_TYPE_BUFFER;
}
+ else if (icon_data_type == ICON_DATA_GPLAYER) {
+ di->type = ICON_TYPE_GPLAYER;
+ }
else {
BLI_assert(0);
}
@@ -1484,6 +1535,15 @@ static void icon_draw_size(
GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
}
}
+ else if (di->type == ICON_TYPE_GPLAYER) {
+ BLI_assert(icon->obj != NULL);
+
+ /* We need to flush widget base first to ensure correct ordering. */
+ UI_widgetbase_draw_cache_flush();
+
+ /* Just draw a colored rect - Like for vicon_colorset_draw() */
+ vicon_gplayer_color_draw(icon, (int)x, (int)y, w, h);
+ }
}
static void ui_id_preview_image_render_size(
@@ -1576,7 +1636,45 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
}
/* reset the icon */
- if (mode == OB_MODE_SCULPT) {
+ if (ob->mode & OB_MODE_GPENCIL_PAINT) {
+ switch (br->gpencil_settings->icon_id) {
+ case GP_BRUSH_ICON_PENCIL:
+ br->id.icon_id = ICON_GPBRUSH_PENCIL;
+ break;
+ case GP_BRUSH_ICON_PEN:
+ br->id.icon_id = ICON_GPBRUSH_PEN;
+ break;
+ case GP_BRUSH_ICON_INK:
+ br->id.icon_id = ICON_GPBRUSH_INK;
+ break;
+ case GP_BRUSH_ICON_INKNOISE:
+ br->id.icon_id = ICON_GPBRUSH_INKNOISE;
+ break;
+ case GP_BRUSH_ICON_BLOCK:
+ br->id.icon_id = ICON_GPBRUSH_BLOCK;
+ break;
+ case GP_BRUSH_ICON_MARKER:
+ br->id.icon_id = ICON_GPBRUSH_MARKER;
+ break;
+ case GP_BRUSH_ICON_FILL:
+ br->id.icon_id = ICON_GPBRUSH_FILL;
+ break;
+ case GP_BRUSH_ICON_ERASE_SOFT:
+ br->id.icon_id = ICON_GPBRUSH_ERASE_SOFT;
+ break;
+ case GP_BRUSH_ICON_ERASE_HARD:
+ br->id.icon_id = ICON_GPBRUSH_ERASE_HARD;
+ break;
+ case GP_BRUSH_ICON_ERASE_STROKE:
+ br->id.icon_id = ICON_GPBRUSH_ERASE_STROKE;
+ break;
+ default:
+ br->id.icon_id = ICON_GPBRUSH_PEN;
+ break;
+ }
+ return id->icon_id;
+ }
+ else if (mode == OB_MODE_SCULPT) {
items = rna_enum_brush_sculpt_tool_items;
tool = br->sculpt_tool;
}
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 82ed4c5acba..89e1a8caec8 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1244,7 +1244,15 @@ void uiItemsFullEnumO(
bool free;
if (ui_layout_is_radial(layout)) {
+ /* XXX: While "_all()" guarantees spatial stability, it's bad when an enum has > 8 items total,
+ * but only a small subset will ever be shown at once (e.g. Mode Switch menu, after the
+ * introduction of GP editing modes)
+ */
+#if 0
RNA_property_enum_items_gettexted_all(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
+#else
+ RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
+#endif
}
else {
RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 131ffbca377..513bfd32191 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -39,6 +39,8 @@
#include "DNA_object_force_types.h"
#include "DNA_brush_types.h"
#include "DNA_texture_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_shader_fx_types.h"
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
@@ -57,6 +59,7 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_idcode.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
@@ -71,6 +74,7 @@
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_screen.h"
+#include "BKE_shader_fx.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -110,7 +114,7 @@ static void template_add_button_search_menu(
const bContext *C, uiLayout *layout, uiBlock *block,
PointerRNA *ptr, PropertyRNA *prop,
uiBlockCreateFunc block_func, void *block_argN, const char * const tip,
- const bool use_previews, const bool editable)
+ const bool use_previews, const bool editable, const bool live_icon)
{
PointerRNA active_ptr = RNA_property_pointer_get(ptr, prop);
ID *id = (active_ptr.data && RNA_struct_is_ID(active_ptr.type)) ? active_ptr.data : NULL;
@@ -146,7 +150,14 @@ static void template_add_button_search_menu(
}
else {
but = uiDefBlockButN(block, block_func, block_argN, "", 0, 0, UI_UNIT_X * 1.6, UI_UNIT_Y, tip);
- ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
+
+ if (live_icon) {
+ int icon = id ? ui_id_icon_get(C, id, false) : RNA_struct_ui_icon(type);
+ ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+ }
+ else {
+ ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
+ }
if (id) {
/* default dragging of icon for id browse buttons */
UI_but_drag_set_id(but, id);
@@ -162,7 +173,8 @@ static uiBlock *template_common_search_menu(
const bContext *C, ARegion *region,
uiButSearchFunc search_func, void *search_arg,
uiButHandleFunc handle_func, void *active_item,
- const int preview_rows, const int preview_cols)
+ const int preview_rows, const int preview_cols,
+ float scale)
{
static char search[256];
wmWindow *win = CTX_wm_window(C);
@@ -177,8 +189,8 @@ static uiBlock *template_common_search_menu(
/* preview thumbnails */
if (preview_rows > 0 && preview_cols > 0) {
- const int w = 4 * U.widget_unit * preview_cols;
- const int h = 5 * U.widget_unit * preview_rows;
+ const int w = 4 * U.widget_unit * preview_cols * scale;
+ const int h = 5 * U.widget_unit * preview_rows * scale;
/* fake button, it holds space for search items */
uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 26, w, h, NULL, 0, 0, 0, 0, NULL);
@@ -237,6 +249,7 @@ typedef struct TemplateID {
short filter;
int prv_rows, prv_cols;
bool preview;
+ float scale;
} TemplateID;
/* Search browse menu, assign */
@@ -382,7 +395,7 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
return template_common_search_menu(
C, ar, id_search_cb_p, &template_ui, template_ID_set_property_cb, active_item_ptr.data,
- template_ui.prv_rows, template_ui.prv_cols);
+ template_ui.prv_rows, template_ui.prv_cols, template_ui.scale);
}
/************************ ID Template ***************************/
@@ -630,7 +643,8 @@ static uiBut *template_id_def_new_but(
static void template_ID(
bContext *C, uiLayout *layout, TemplateID *template_ui, StructRNA *type, int flag,
- const char *newop, const char *openop, const char *unlinkop)
+ const char *newop, const char *openop, const char *unlinkop,
+ const bool live_icon)
{
uiBut *but;
uiBlock *block;
@@ -655,7 +669,7 @@ static void template_ID(
template_add_button_search_menu(
C, layout, block, &template_ui->ptr, template_ui->prop,
id_search_menu, MEM_dupallocN(template_ui), TIP_(template_id_browse_tip(type)),
- use_previews, editable);
+ use_previews, editable, live_icon);
}
/* text button with name */
@@ -860,7 +874,8 @@ static void ui_template_id(
uiLayout *layout, bContext *C,
PointerRNA *ptr, const char *propname,
const char *newop, const char *openop, const char *unlinkop,
- int flag, int prv_rows, int prv_cols, int filter, bool use_tabs)
+ int flag, int prv_rows, int prv_cols, int filter, bool use_tabs,
+ float scale, bool live_icon)
{
TemplateID *template_ui;
PropertyRNA *prop;
@@ -879,6 +894,7 @@ static void ui_template_id(
template_ui->prop = prop;
template_ui->prv_rows = prv_rows;
template_ui->prv_cols = prv_cols;
+ template_ui->scale = scale;
if ((flag & UI_ID_PIN) == 0) {
template_ui->filter = filter;
@@ -907,7 +923,7 @@ static void ui_template_id(
}
else {
uiLayoutRow(layout, true);
- template_ID(C, layout, template_ui, type, flag, newop, openop, unlinkop);
+ template_ID(C, layout, template_ui, type, flag, newop, openop, unlinkop, live_icon);
}
}
@@ -916,13 +932,14 @@ static void ui_template_id(
void uiTemplateID(
uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop, int filter)
+ const char *openop, const char *unlinkop,
+ int filter, const bool live_icon)
{
ui_template_id(
layout, C, ptr, propname,
newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE,
- 0, 0, filter, false);
+ 0, 0, filter, false, 1.0f, live_icon);
}
void uiTemplateIDBrowse(
@@ -933,7 +950,7 @@ void uiTemplateIDBrowse(
layout, C, ptr, propname,
newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME,
- 0, 0, filter, false);
+ 0, 0, filter, false, 1.0f, false);
}
void uiTemplateIDPreview(
@@ -944,7 +961,18 @@ void uiTemplateIDPreview(
layout, C, ptr, propname,
newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS,
- rows, cols, filter, false);
+ rows, cols, filter, false, 1.0f, false);
+}
+
+void uiTemplateGpencilColorPreview(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname,
+ int rows, int cols, float scale, int filter)
+{
+ ui_template_id(
+ layout, C, ptr, propname,
+ NULL, NULL, NULL,
+ UI_ID_BROWSE | UI_ID_PREVIEWS | UI_ID_DELETE,
+ rows, cols, filter, false, scale < 0.5f ? 0.5f : scale, false);
}
/**
@@ -960,7 +988,7 @@ void uiTemplateIDTabs(
layout, C, ptr, propname,
newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE,
- 0, 0, filter, true);
+ 0, 0, filter, true, 1.0f, false);
}
/************************ ID Chooser Template ***************************/
@@ -1057,12 +1085,12 @@ static uiBlock *template_search_menu(bContext *C, ARegion *region, void *arg_tem
return template_common_search_menu(
C, region, ui_rna_collection_search_cb, &template_search,
template_search_handle_cb, active_ptr.data,
- template_search.preview_rows, template_search.preview_cols);
+ template_search.preview_rows, template_search.preview_cols, 1.0f);
}
static void template_search_add_button_searchmenu(
const bContext *C, uiLayout *layout, uiBlock *block,
- TemplateSearch *template_search, const bool editable)
+ TemplateSearch *template_search, const bool editable, const bool live_icon)
{
const char *ui_description = RNA_property_ui_description(template_search->search_data.target_prop);
@@ -1070,7 +1098,7 @@ static void template_search_add_button_searchmenu(
C, layout, block,
&template_search->search_data.target_ptr, template_search->search_data.target_prop,
template_search_menu, MEM_dupallocN(template_search), ui_description,
- template_search->use_previews, editable);
+ template_search->use_previews, editable, live_icon);
}
static void template_search_add_button_name(
@@ -1116,7 +1144,7 @@ static void template_search_buttons(
uiLayoutRow(layout, true);
UI_block_align_begin(block);
- template_search_add_button_searchmenu(C, layout, block, template_search, editable);
+ template_search_add_button_searchmenu(C, layout, block, template_search, editable, false);
template_search_add_button_name(block, &active_ptr, type);
template_search_add_button_operator(block, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, editable);
template_search_add_button_operator(block, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, editable);
@@ -1539,6 +1567,246 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
return NULL;
}
+/************************ Grease Pencil Modifier Template *************************/
+
+static uiLayout *gpencil_draw_modifier(uiLayout *layout, Object *ob,
+ GpencilModifierData *md)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ PointerRNA ptr;
+ uiBlock *block;
+ uiLayout *box, *column, *row, *sub;
+ uiLayout *result = NULL;
+
+ /* create RNA pointer */
+ RNA_pointer_create(&ob->id, &RNA_GpencilModifier, md, &ptr);
+
+ column = uiLayoutColumn(layout, true);
+ uiLayoutSetContextPointer(column, "modifier", &ptr);
+
+ /* rounded header ------------------------------------------------------------------- */
+ box = uiLayoutBox(column);
+
+ row = uiLayoutRow(box, false);
+ block = uiLayoutGetBlock(row);
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ /* Open/Close ................................. */
+ uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE);
+
+ /* modifier-type icon */
+ uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ /* modifier name */
+ if (mti->isDisabled && mti->isDisabled(md, 0)) {
+ uiLayoutSetRedAlert(row, true);
+ }
+ uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
+ uiLayoutSetRedAlert(row, false);
+
+ /* mode enabling buttons */
+ UI_block_align_begin(block);
+ uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE);
+ uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE);
+
+ if (mti->flags & eGpencilModifierTypeFlag_SupportsEditmode) {
+ sub = uiLayoutRow(row, true);
+ uiLayoutSetActive(sub, false);
+ uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE);
+ }
+
+ UI_block_align_end(block);
+
+ /* Up/Down + Delete ........................... */
+ UI_block_align_begin(block);
+ uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_gpencil_modifier_move_up");
+ uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_gpencil_modifier_move_down");
+ UI_block_align_end(block);
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ uiItemO(row, "", ICON_X, "OBJECT_OT_gpencil_modifier_remove");
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ /* modifier settings (under the header) --------------------------------------------------- */
+ if (md->mode & eGpencilModifierMode_Expanded) {
+ /* apply/convert/copy */
+ box = uiLayoutBox(column);
+ row = uiLayoutRow(box, false);
+
+ /* only here obdata, the rest of modifiers is ob level */
+ UI_block_lock_set(block, BKE_object_obdata_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
+ uiItemEnumO(row, "OBJECT_OT_gpencil_modifier_apply", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"),
+ 0, "apply_as", MODIFIER_APPLY_DATA);
+
+ uiItemO(row, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"), ICON_NONE,
+ "OBJECT_OT_gpencil_modifier_copy");
+
+ /* result is the layout block inside the box, that we return so that modifier settings can be drawn */
+ result = uiLayoutColumn(box, false);
+ block = uiLayoutAbsoluteBlock(box);
+ }
+
+ /* error messages */
+ if (md->error) {
+ box = uiLayoutBox(column);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, md->error, ICON_ERROR);
+ }
+
+ return result;
+}
+
+uiLayout *uiTemplateGpencilModifier(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ Object *ob;
+ GpencilModifierData *md, *vmd;
+ int i;
+
+ /* verify we have valid data */
+ if (!RNA_struct_is_a(ptr->type, &RNA_GpencilModifier)) {
+ RNA_warning("Expected modifier on object");
+ return NULL;
+ }
+
+ ob = ptr->id.data;
+ md = ptr->data;
+
+ if (!ob || !(GS(ob->id.name) == ID_OB)) {
+ RNA_warning("Expected modifier on object");
+ return NULL;
+ }
+
+ UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE);
+
+ /* find modifier and draw it */
+ vmd = ob->greasepencil_modifiers.first;
+ for (i = 0; vmd; i++, vmd = vmd->next) {
+ if (md == vmd)
+ return gpencil_draw_modifier(layout, ob, md);
+ }
+
+ return NULL;
+}
+
+/************************ Shader FX Template *************************/
+
+static uiLayout *gpencil_draw_shaderfx(uiLayout *layout, Object *ob,
+ ShaderFxData *md)
+{
+ const ShaderFxTypeInfo *mti = BKE_shaderfxType_getInfo(md->type);
+ PointerRNA ptr;
+ uiBlock *block;
+ uiLayout *box, *column, *row, *sub;
+ uiLayout *result = NULL;
+
+ /* create RNA pointer */
+ RNA_pointer_create(&ob->id, &RNA_ShaderFx, md, &ptr);
+
+ column = uiLayoutColumn(layout, true);
+ uiLayoutSetContextPointer(column, "shaderfx", &ptr);
+
+ /* rounded header ------------------------------------------------------------------- */
+ box = uiLayoutBox(column);
+
+ row = uiLayoutRow(box, false);
+ block = uiLayoutGetBlock(row);
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ /* Open/Close ................................. */
+ uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE);
+
+ /* shader-type icon */
+ uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ /* effect name */
+ if (mti->isDisabled && mti->isDisabled(md, 0)) {
+ uiLayoutSetRedAlert(row, true);
+ }
+ uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
+ uiLayoutSetRedAlert(row, false);
+
+ /* mode enabling buttons */
+ UI_block_align_begin(block);
+ uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE);
+ uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE);
+
+ if (mti->flags & eShaderFxTypeFlag_SupportsEditmode) {
+ sub = uiLayoutRow(row, true);
+ uiLayoutSetActive(sub, false);
+ uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE);
+ }
+
+ UI_block_align_end(block);
+
+ /* Up/Down + Delete ........................... */
+ UI_block_align_begin(block);
+ uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_shaderfx_move_up");
+ uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_shaderfx_move_down");
+ UI_block_align_end(block);
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ uiItemO(row, "", ICON_X, "OBJECT_OT_shaderfx_remove");
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ /* effect settings (under the header) --------------------------------------------------- */
+ if (md->mode & eShaderFxMode_Expanded) {
+ /* apply/convert/copy */
+ box = uiLayoutBox(column);
+ row = uiLayoutRow(box, false);
+
+ /* only here obdata, the rest of effect is ob level */
+ UI_block_lock_set(block, BKE_object_obdata_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ /* result is the layout block inside the box, that we return so that effect settings can be drawn */
+ result = uiLayoutColumn(box, false);
+ block = uiLayoutAbsoluteBlock(box);
+ }
+
+ /* error messages */
+ if (md->error) {
+ box = uiLayoutBox(column);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, md->error, ICON_ERROR);
+ }
+
+ return result;
+}
+
+uiLayout *uiTemplateShaderFx(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ Object *ob;
+ ShaderFxData *fx, *vfx;
+ int i;
+
+ /* verify we have valid data */
+ if (!RNA_struct_is_a(ptr->type, &RNA_ShaderFx)) {
+ RNA_warning("Expected shader fx on object");
+ return NULL;
+ }
+
+ ob = ptr->id.data;
+ fx = ptr->data;
+
+ if (!ob || !(GS(ob->id.name) == ID_OB)) {
+ RNA_warning("Expected shader fx on object");
+ return NULL;
+ }
+
+ UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE);
+
+ /* find modifier and draw it */
+ vfx = ob->shader_fx.first;
+ for (i = 0; vfx; i++, vfx = vfx->next) {
+ if (fx == vfx)
+ return gpencil_draw_shaderfx(layout, ob, fx);
+ }
+
+ return NULL;
+}
/************************ Redo Buttons Template *************************/
@@ -4638,7 +4906,7 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr);
- uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!file) {
return;
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 3cb8a277e9a..e6422c423b9 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -1536,15 +1536,6 @@ void init_userdef_do_versions(Main *bmain)
#undef USER_VERSION_ATLEAST
#define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST((&(U)), ver, subver)
-
- if (!USER_VERSION_ATLEAST(269, 9)) {
- /* grease pencil - new layer color */
- if (U.gpencil_new_layer_col[3] < 0.1f) {
- /* defaults to black, but must at least be visible! */
- U.gpencil_new_layer_col[3] = 0.9f;
- }
- }
-
if (!USER_VERSION_ATLEAST(271, 5)) {
U.pie_menu_radius = 100;
U.pie_menu_threshold = 12;
@@ -1582,6 +1573,17 @@ void init_userdef_do_versions(Main *bmain)
for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) {
memcpy(btheme, &U_theme_default, sizeof(*btheme));
}
+
+ /* Annotations - new layer color
+ * Replace anything that used to be set if it looks like was left
+ * on the old default (i.e. black), which most users used
+ */
+ if ((U.gpencil_new_layer_col[3] < 0.1f) || (U.gpencil_new_layer_col[0] < 0.1f)) {
+ /* - New color matches the annotation pencil icon
+ * - Non-full alpha looks better!
+ */
+ ARRAY_SET_ITEMS(U.gpencil_new_layer_col, 0.38f, 0.61f, 0.78f, 0.9f);
+ }
}
/**
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index 305e3287029..739975a6278 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -31,6 +31,8 @@ set(INC
../../makesdna
../../makesrna
../../modifiers
+ ../../gpencil_modifiers
+ ../../shader_fx
../../python
../../render/extern/include
../../windowmanager
@@ -53,6 +55,8 @@ set(SRC
object_hook.c
object_modes.c
object_modifier.c
+ object_gpencil_modifier.c
+ object_shader_fx.c
object_ops.c
object_random.c
object_relations.c
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 68e84ec3f3b..87eddc2674c 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -71,6 +71,7 @@
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_font.h"
+#include "BKE_gpencil.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_layer.h"
@@ -103,6 +104,7 @@
#include "ED_armature.h"
#include "ED_curve.h"
+#include "ED_gpencil.h"
#include "ED_mball.h"
#include "ED_mesh.h"
#include "ED_node.h"
@@ -985,6 +987,106 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot)
ED_object_add_generic_props(ot, false);
}
+/********************* Add Gpencil Operator ********************/
+
+static int object_gpencil_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (ob && (ob->type == OB_GPENCIL)) ? ob->data : NULL;
+
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ float loc[3], rot[3];
+ unsigned int layer;
+ bool newob = false;
+
+ /* Hack: Force view-align to be on by default
+ * since it's not nice for adding shapes in 2D
+ * for them to end up aligned oddly, but only for Monkey
+ */
+ if ((RNA_struct_property_is_set(op->ptr, "view_align") == false) &&
+ (type == GP_MONKEY)) {
+ RNA_boolean_set(op->ptr, "view_align", true);
+ }
+
+ /* Note: We use 'Y' here (not 'Z'), as */
+ WM_operator_view3d_unit_defaults(C, op);
+ if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, &layer, NULL))
+ return OPERATOR_CANCELLED;
+
+ /* add new object if not currently editing a GP object,
+ * or if "empty" was chosen (i.e. user wants a blank GP canvas)
+ */
+ if ((gpd == NULL) || (GPENCIL_ANY_MODE(gpd) == false) || (type == GP_EMPTY)) {
+ const char *ob_name = (type == GP_MONKEY) ? "Suzanne" : NULL;
+ float radius = RNA_float_get(op->ptr, "radius");
+
+ ob = ED_object_add_type(C, OB_GPENCIL, ob_name, loc, rot, true, layer);
+ gpd = ob->data;
+ newob = true;
+
+ BKE_object_obdata_size_init(ob, GP_OBGPENCIL_DEFAULT_SIZE * radius);
+ }
+ else {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_ADDED, NULL);
+ }
+
+ /* create relevant geometry */
+ switch (type) {
+ case GP_MONKEY:
+ {
+ float radius = RNA_float_get(op->ptr, "radius");
+ float mat[4][4];
+
+ ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
+ mul_v3_fl(mat[0], radius);
+ mul_v3_fl(mat[1], radius);
+ mul_v3_fl(mat[2], radius);
+
+ ED_gpencil_create_monkey(C, mat);
+ break;
+ }
+
+ case GP_EMPTY:
+ /* do nothing */
+ break;
+
+ default:
+ BKE_report(op->reports, RPT_WARNING, "Not implemented");
+ break;
+ }
+
+ /* if this is a new object, initialise default stuff (colors, etc.) */
+ if (newob) {
+ ED_gpencil_add_defaults(C);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_gpencil_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add GPencil";
+ ot->description = "Add a grease pencil object to the scene";
+ ot->idname = "OBJECT_OT_gpencil_add";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = object_gpencil_add_exec;
+ ot->poll = ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ED_object_add_unit_props(ot);
+ ED_object_add_generic_props(ot, false);
+
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", "");
+}
+
/********************* Add Light Operator ********************/
static const char *get_light_defname(int type)
@@ -1781,6 +1883,10 @@ static int convert_exec(bContext *C, wmOperator *op)
if (ob->type == OB_MESH) {
BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */
}
+ if (ob->type == OB_GPENCIL) {
+ BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */
+ BKE_object_free_shaderfx(ob, 0);
+ }
}
}
else if (ob->type == OB_MESH && target == OB_CURVE) {
@@ -2122,6 +2228,10 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer
ID_NEW_REMAP_US(obn->mat[a])
else {
obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a]));
+ /* duplicate grease pencil settings */
+ if (ob->mat[a]->gp_style) {
+ obn->mat[a]->gp_style = MEM_dupallocN(ob->mat[a]->gp_style);
+ }
}
id_us_min(id);
@@ -2258,6 +2368,16 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer
id_us_min(id);
}
break;
+ case OB_GPENCIL:
+ if (dupflag != 0) {
+ ID_NEW_REMAP_US2(obn->data)
+ else {
+ obn->data = ID_NEW_SET(obn->data, BKE_gpencil_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
}
/* check if obdata is copied */
@@ -2482,7 +2602,7 @@ static bool join_poll(bContext *C)
if (!ob || ID_IS_LINKED(ob)) return 0;
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE))
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE, OB_GPENCIL))
return ED_operator_screenactive(C);
else
return 0;
@@ -2500,6 +2620,13 @@ static int join_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata");
return OPERATOR_CANCELLED;
}
+ else if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if ((!gpd) || GPENCIL_ANY_MODE(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "This data does not support joining in this mode");
+ return OPERATOR_CANCELLED;
+ }
+ }
if (ob->type == OB_MESH)
return join_mesh_exec(C, op);
@@ -2507,6 +2634,8 @@ static int join_exec(bContext *C, wmOperator *op)
return join_curve_exec(C, op);
else if (ob->type == OB_ARMATURE)
return join_armature_exec(C, op);
+ else if (ob->type == OB_GPENCIL)
+ return ED_gpencil_join_objects_exec(C, op);
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index a6c3c86922d..48048319cb7 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -100,6 +100,7 @@
#include "ED_screen.h"
#include "ED_undo.h"
#include "ED_image.h"
+#include "ED_gpencil.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -1539,7 +1540,6 @@ static const EnumPropertyItem *object_mode_set_itemsf(
const EnumPropertyItem *input = rna_enum_object_mode_items;
EnumPropertyItem *item = NULL;
Object *ob;
- bGPdata *gpd;
int totitem = 0;
if (!C) /* needed for docs */
@@ -1555,7 +1555,9 @@ static const EnumPropertyItem *object_mode_set_itemsf(
(input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) ||
(input->value == OB_MODE_PARTICLE_EDIT && use_mode_particle_edit) ||
(ELEM(input->value, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT,
- OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) ||
+ OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) ||
+ (ELEM(input->value, OB_MODE_GPENCIL_EDIT, OB_MODE_GPENCIL_PAINT,
+ OB_MODE_GPENCIL_SCULPT, OB_MODE_GPENCIL_WEIGHT) && (ob->type == OB_GPENCIL)) ||
(input->value == OB_MODE_OBJECT))
{
RNA_enum_item_add(&item, &totitem, input);
@@ -1568,14 +1570,6 @@ static const EnumPropertyItem *object_mode_set_itemsf(
RNA_enum_items_add_value(&item, &totitem, input, OB_MODE_OBJECT);
}
- /* On top of all the rest, GPencil Stroke Edit Mode
- * is available if there's a valid gp datablock...
- */
- gpd = CTX_data_gpencil_data(C);
- if (gpd) {
- RNA_enum_items_add_value(&item, &totitem, rna_enum_object_mode_items, OB_MODE_GPENCIL);
- }
-
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -1600,7 +1594,6 @@ static int object_mode_set_exec(bContext *C, wmOperator *op)
{
bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_or_submode");
Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = CTX_data_gpencil_data(C);
eObjectMode mode = RNA_enum_get(op->ptr, "mode");
eObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT;
const bool toggle = RNA_boolean_get(op->ptr, "toggle");
@@ -1620,22 +1613,9 @@ static int object_mode_set_exec(bContext *C, wmOperator *op)
}
}
- if (gpd) {
- /* GP Mode is not bound to a specific object. Therefore,
- * we don't want it to be actually saved on any objects,
- * as weirdness can happen if you select other objects,
- * or load old files.
- *
- * Instead, we use the following 2 rules to ensure that
- * the mode selector works as expected:
- * 1) If there's no object, we want to enter editmode.
- * (i.e. with no object, we're in object mode)
- * 2) Otherwise, exit stroke editmode, so that we can
- * enter another mode...
- */
- if (!ob || (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
- WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_EXEC_REGION_WIN, NULL);
- }
+ /* by default the operator assume is a mesh, but if gp object change mode */
+ if ((ob != NULL) && (ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) {
+ mode = OB_MODE_GPENCIL_EDIT;
}
if (!ob || !ED_object_mode_compat_test(ob, mode))
@@ -1666,6 +1646,14 @@ static int object_mode_set_exec(bContext *C, wmOperator *op)
}
}
+ /* if type is OB_GPENCIL, set cursor mode */
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ if (ob->data) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ ED_gpencil_setup_modes(C, gpd, ob->mode);
+ }
+ }
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
new file mode 100644
index 00000000000..175fb1706fb
--- /dev/null
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -0,0 +1,637 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2018
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/object/object_gpencil_modifier.c
+ * \ingroup edobj
+ */
+
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_report.h"
+#include "BKE_object.h"
+#include "BKE_gpencil.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "object_intern.h"
+
+/******************************** API ****************************/
+
+GpencilModifierData *ED_object_gpencil_modifier_add(
+ ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
+{
+ GpencilModifierData *new_md = NULL;
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
+
+ if (ob->type != OB_GPENCIL) {
+ BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2);
+ return NULL;
+ }
+
+ if (mti->flags & eGpencilModifierTypeFlag_Single) {
+ if (BKE_gpencil_modifiers_findByType(ob, type)) {
+ BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
+ return NULL;
+ }
+ }
+
+ /* get new modifier data to add */
+ new_md = BKE_gpencil_modifier_new(type);
+
+ BLI_addtail(&ob->greasepencil_modifiers, new_md);
+
+ if (name) {
+ BLI_strncpy_utf8(new_md->name, name, sizeof(new_md->name));
+ }
+
+ /* make sure modifier data has unique name */
+ BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, new_md);
+
+
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+
+ return new_md;
+}
+
+/* Return true if the object has a modifier of type 'type' other than
+ * the modifier pointed to be 'exclude', otherwise returns false. */
+static bool UNUSED_FUNCTION(gpencil_object_has_modifier)(
+ const Object *ob, const GpencilModifierData *exclude,
+ GpencilModifierType type)
+{
+ GpencilModifierData *md;
+
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if ((md != exclude) && (md->type == type))
+ return true;
+ }
+
+ return false;
+}
+
+static bool gpencil_object_modifier_remove(
+ Main *bmain, Object *ob, GpencilModifierData *md,
+ bool *UNUSED(r_sort_depsgraph))
+{
+ /* It seems on rapid delete it is possible to
+ * get called twice on same modifier, so make
+ * sure it is in list. */
+ if (BLI_findindex(&ob->greasepencil_modifiers, md) == -1) {
+ return 0;
+ }
+
+ DEG_relations_tag_update(bmain);
+
+ BLI_remlink(&ob->greasepencil_modifiers, md);
+ BKE_gpencil_modifier_free(md);
+ BKE_object_free_derived_caches(ob);
+
+ return 1;
+}
+
+bool ED_object_gpencil_modifier_remove(ReportList *reports, Main *bmain, Object *ob, GpencilModifierData *md)
+{
+ bool sort_depsgraph = false;
+ bool ok;
+
+ ok = gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph);
+
+ if (!ok) {
+ BKE_reportf(reports, RPT_ERROR, "Modifier '%s' not in object '%s'", md->name, ob->id.name);
+ return 0;
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+
+ return 1;
+}
+
+void ED_object_gpencil_modifier_clear(Main *bmain, Object *ob)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+ bool sort_depsgraph = false;
+
+ if (!md)
+ return;
+
+ while (md) {
+ GpencilModifierData *next_md;
+
+ next_md = md->next;
+
+ gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph);
+
+ md = next_md;
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+}
+
+int ED_object_gpencil_modifier_move_up(ReportList *UNUSED(reports), Object *ob, GpencilModifierData *md)
+{
+ if (md->prev) {
+ BLI_remlink(&ob->greasepencil_modifiers, md);
+ BLI_insertlinkbefore(&ob->greasepencil_modifiers, md->prev, md);
+ }
+
+ return 1;
+}
+
+int ED_object_gpencil_modifier_move_down(ReportList *UNUSED(reports), Object *ob, GpencilModifierData *md)
+{
+ if (md->next) {
+ BLI_remlink(&ob->greasepencil_modifiers, md);
+ BLI_insertlinkafter(&ob->greasepencil_modifiers, md->next, md);
+ }
+
+ return 1;
+}
+
+static int gpencil_modifier_apply_obdata(
+ ReportList *reports, Main *bmain, Depsgraph *depsgraph, Object *ob, GpencilModifierData *md)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti->isDisabled && mti->isDisabled(md, 0)) {
+ BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
+ return 0;
+ }
+
+ if (ob->type == OB_GPENCIL) {
+ if (ELEM(NULL, ob, ob->data)) {
+ return 0;
+ }
+ else if (mti->bakeModifier == NULL) {
+ BKE_report(reports, RPT_ERROR, "Not implemented");
+ return 0;
+ }
+ mti->bakeModifier(bmain, depsgraph, md, ob);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ else {
+ BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
+ return 0;
+ }
+
+ return 1;
+}
+
+int ED_object_gpencil_modifier_apply(
+ Main *bmain, ReportList *reports, Depsgraph *depsgraph,
+ Object *ob, GpencilModifierData *md, int UNUSED(mode))
+{
+
+ if (ob->type == OB_GPENCIL) {
+ if (ob->mode != OB_MODE_OBJECT) {
+ BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in paint, sculpt or edit mode");
+ return 0;
+ }
+
+ if (((ID *)ob->data)->us > 1) {
+ BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
+ return 0;
+ }
+ }
+ else if (((ID *)ob->data)->us > 1) {
+ BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
+ return 0;
+ }
+
+ if (md != ob->greasepencil_modifiers.first)
+ BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected");
+
+ if (!gpencil_modifier_apply_obdata(reports, bmain, depsgraph, ob, md)) {
+ return 0;
+ }
+
+ BLI_remlink(&ob->greasepencil_modifiers, md);
+ BKE_gpencil_modifier_free(md);
+
+ return 1;
+}
+
+int ED_object_gpencil_modifier_copy(ReportList *UNUSED(reports), Object *ob, GpencilModifierData *md)
+{
+ GpencilModifierData *nmd;
+
+ nmd = BKE_gpencil_modifier_new(md->type);
+ BKE_gpencil_modifier_copyData(md, nmd);
+ BLI_insertlinkafter(&ob->greasepencil_modifiers, md, nmd);
+ BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, nmd);
+
+ return 1;
+}
+
+/************************ add modifier operator *********************/
+
+static int gpencil_modifier_add_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = ED_object_active_context(C);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ if (!ED_object_gpencil_modifier_add(op->reports, bmain, scene, ob, NULL, type))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static const EnumPropertyItem *gpencil_modifier_add_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ Object *ob = ED_object_active_context(C);
+ EnumPropertyItem *item = NULL;
+ const EnumPropertyItem *md_item, *group_item = NULL;
+ const GpencilModifierTypeInfo *mti;
+ int totitem = 0, a;
+
+ if (!ob)
+ return rna_enum_object_greasepencil_modifier_type_items;
+
+ for (a = 0; rna_enum_object_greasepencil_modifier_type_items[a].identifier; a++) {
+ md_item = &rna_enum_object_greasepencil_modifier_type_items[a];
+ if (md_item->identifier[0]) {
+ mti = BKE_gpencil_modifierType_getInfo(md_item->value);
+
+ if (mti->flags & eGpencilModifierTypeFlag_NoUserAdd)
+ continue;
+ }
+ else {
+ group_item = md_item;
+ md_item = NULL;
+
+ continue;
+ }
+
+ if (group_item) {
+ RNA_enum_item_add(&item, &totitem, group_item);
+ group_item = NULL;
+ }
+
+ RNA_enum_item_add(&item, &totitem, md_item);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+void OBJECT_OT_gpencil_modifier_add(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Add Grease Pencil Modifier";
+ ot->description = "Add a procedural operation/effect to the active grease pencil object";
+ ot->idname = "OBJECT_OT_gpencil_modifier_add";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gpencil_modifier_add_exec;
+ ot->poll = ED_operator_object_active_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "type", rna_enum_object_modifier_type_items, eGpencilModifierType_Thick, "Type", "");
+ RNA_def_enum_funcs(prop, gpencil_modifier_add_itemf);
+ ot->prop = prop;
+}
+
+/************************ generic functions for operators using mod names and data context *********************/
+
+static int gpencil_edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag)
+{
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type);
+ Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C);
+
+ if (!ptr.data) {
+ CTX_wm_operator_poll_msg_set(C, "Context missing 'modifier'");
+ return 0;
+ }
+
+ if (!ob || ID_IS_LINKED(ob)) return 0;
+ if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0;
+ if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) return 0;
+
+ if (ID_IS_STATIC_OVERRIDE(ob)) {
+ CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers comming from static override");
+ return (((GpencilModifierData *)ptr.data)->flag & eGpencilModifierFlag_StaticOverride_Local) != 0;
+ }
+
+ return 1;
+}
+
+static bool gpencil_edit_modifier_poll(bContext *C)
+{
+ return gpencil_edit_modifier_poll_generic(C, &RNA_GpencilModifier, 0);
+}
+
+static void gpencil_edit_modifier_properties(wmOperatorType *ot)
+{
+ RNA_def_string(ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit");
+}
+
+static int gpencil_edit_modifier_invoke_properties(bContext *C, wmOperator *op)
+{
+ GpencilModifierData *md;
+
+ if (RNA_struct_property_is_set(op->ptr, "modifier")) {
+ return true;
+ }
+ else {
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_GpencilModifier);
+ if (ptr.data) {
+ md = ptr.data;
+ RNA_string_set(op->ptr, "modifier", md->name);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op, Object *ob, int type)
+{
+ char modifier_name[MAX_NAME];
+ GpencilModifierData *md;
+ RNA_string_get(op->ptr, "modifier", modifier_name);
+
+ md = BKE_gpencil_modifiers_findByName(ob, modifier_name);
+
+ if (md && type != 0 && md->type != type)
+ md = NULL;
+
+ return md;
+}
+
+/************************ remove modifier operator *********************/
+
+static int gpencil_modifier_remove_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = ED_object_active_context(C);
+ GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
+
+ if (!md || !ED_object_gpencil_modifier_remove(op->reports, bmain, ob, md))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int gpencil_modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op))
+ return gpencil_modifier_remove_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_gpencil_modifier_remove(wmOperatorType *ot)
+{
+ ot->name = "Remove Grease Pencil Modifier";
+ ot->description = "Remove a modifier from the active grease pencil object";
+ ot->idname = "OBJECT_OT_gpencil_modifier_remove";
+
+ ot->invoke = gpencil_modifier_remove_invoke;
+ ot->exec = gpencil_modifier_remove_exec;
+ ot->poll = gpencil_edit_modifier_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ gpencil_edit_modifier_properties(ot);
+}
+
+/************************ move up modifier operator *********************/
+
+static int gpencil_modifier_move_up_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
+
+ if (!md || !ED_object_gpencil_modifier_move_up(op->reports, ob, md))
+ return OPERATOR_CANCELLED;
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int gpencil_modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op))
+ return gpencil_modifier_move_up_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_gpencil_modifier_move_up(wmOperatorType *ot)
+{
+ ot->name = "Move Up Modifier";
+ ot->description = "Move modifier up in the stack";
+ ot->idname = "OBJECT_OT_gpencil_modifier_move_up";
+
+ ot->invoke = gpencil_modifier_move_up_invoke;
+ ot->exec = gpencil_modifier_move_up_exec;
+ ot->poll = gpencil_edit_modifier_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ gpencil_edit_modifier_properties(ot);
+}
+
+/************************ move down modifier operator *********************/
+
+static int gpencil_modifier_move_down_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
+
+ if (!md || !ED_object_gpencil_modifier_move_down(op->reports, ob, md))
+ return OPERATOR_CANCELLED;
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int gpencil_modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op))
+ return gpencil_modifier_move_down_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_gpencil_modifier_move_down(wmOperatorType *ot)
+{
+ ot->name = "Move Down Modifier";
+ ot->description = "Move modifier down in the stack";
+ ot->idname = "OBJECT_OT_gpencil_modifier_move_down";
+
+ ot->invoke = gpencil_modifier_move_down_invoke;
+ ot->exec = gpencil_modifier_move_down_exec;
+ ot->poll = gpencil_edit_modifier_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ gpencil_edit_modifier_properties(ot);
+}
+
+/************************ apply modifier operator *********************/
+
+static int gpencil_modifier_apply_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = ED_object_active_context(C);
+ GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
+ int apply_as = RNA_enum_get(op->ptr, "apply_as");
+
+ if (!md || !ED_object_gpencil_modifier_apply(bmain, op->reports, depsgraph, ob, md, apply_as)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int gpencil_modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op))
+ return gpencil_modifier_apply_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+static const EnumPropertyItem gpencil_modifier_apply_as_items[] = {
+ {MODIFIER_APPLY_DATA, "DATA", 0, "Object Data", "Apply modifier to the object's data"},
+ {MODIFIER_APPLY_SHAPE, "SHAPE", 0, "New Shape", "Apply deform-only modifier to a new shape on this object"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+void OBJECT_OT_gpencil_modifier_apply(wmOperatorType *ot)
+{
+ ot->name = "Apply Modifier";
+ ot->description = "Apply modifier and remove from the stack";
+ ot->idname = "OBJECT_OT_gpencil_modifier_apply";
+
+ ot->invoke = gpencil_modifier_apply_invoke;
+ ot->exec = gpencil_modifier_apply_exec;
+ ot->poll = gpencil_edit_modifier_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_enum(ot->srna, "apply_as", gpencil_modifier_apply_as_items, MODIFIER_APPLY_DATA, "Apply as", "How to apply the modifier to the geometry");
+ gpencil_edit_modifier_properties(ot);
+}
+
+/************************ copy modifier operator *********************/
+
+static int gpencil_modifier_copy_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
+
+ if (!md || !ED_object_gpencil_modifier_copy(op->reports, ob, md))
+ return OPERATOR_CANCELLED;
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int gpencil_modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op))
+ return gpencil_modifier_copy_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_gpencil_modifier_copy(wmOperatorType *ot)
+{
+ ot->name = "Copy Modifier";
+ ot->description = "Duplicate modifier at the same position in the stack";
+ ot->idname = "OBJECT_OT_gpencil_modifier_copy";
+
+ ot->invoke = gpencil_modifier_copy_invoke;
+ ot->exec = gpencil_modifier_copy_exec;
+ ot->poll = gpencil_edit_modifier_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ gpencil_edit_modifier_properties(ot);
+}
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 1b5c6df2632..ef8653541f0 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -115,6 +115,7 @@ void OBJECT_OT_armature_add(struct wmOperatorType *ot);
void OBJECT_OT_empty_add(struct wmOperatorType *ot);
void OBJECT_OT_lightprobe_add(struct wmOperatorType *ot);
void OBJECT_OT_drop_named_image(struct wmOperatorType *ot);
+void OBJECT_OT_gpencil_add(struct wmOperatorType *ot);
void OBJECT_OT_light_add(struct wmOperatorType *ot);
void OBJECT_OT_effector_add(struct wmOperatorType *ot);
void OBJECT_OT_camera_add(struct wmOperatorType *ot);
@@ -175,6 +176,20 @@ void OBJECT_OT_skin_armature_create(struct wmOperatorType *ot);
void OBJECT_OT_laplaciandeform_bind(struct wmOperatorType *ot);
void OBJECT_OT_surfacedeform_bind(struct wmOperatorType *ot);
+/* grease pencil modifiers */
+void OBJECT_OT_gpencil_modifier_add(struct wmOperatorType *ot);
+void OBJECT_OT_gpencil_modifier_remove(struct wmOperatorType *ot);
+void OBJECT_OT_gpencil_modifier_move_up(struct wmOperatorType *ot);
+void OBJECT_OT_gpencil_modifier_move_down(struct wmOperatorType *ot);
+void OBJECT_OT_gpencil_modifier_apply(struct wmOperatorType *ot);
+void OBJECT_OT_gpencil_modifier_copy(struct wmOperatorType *ot);
+
+/* shader fx */
+void OBJECT_OT_shaderfx_add(struct wmOperatorType *ot);
+void OBJECT_OT_shaderfx_remove(struct wmOperatorType *ot);
+void OBJECT_OT_shaderfx_move_up(struct wmOperatorType *ot);
+void OBJECT_OT_shaderfx_move_down(struct wmOperatorType *ot);
+
/* object_constraint.c */
void OBJECT_OT_constraint_add(struct wmOperatorType *ot);
void OBJECT_OT_constraint_add_with_targets(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index e9bd6fbce8f..261f7f42bc0 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -27,6 +27,7 @@
* actual mode switching logic is per-object type.
*/
+#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_workspace_types.h"
@@ -71,8 +72,14 @@ static const char *object_mode_op_string(eObjectMode mode)
return "PARTICLE_OT_particle_edit_toggle";
if (mode == OB_MODE_POSE)
return "OBJECT_OT_posemode_toggle";
- if (mode == OB_MODE_GPENCIL)
+ if (mode == OB_MODE_GPENCIL_EDIT)
return "GPENCIL_OT_editmode_toggle";
+ if (mode == OB_MODE_GPENCIL_PAINT)
+ return "GPENCIL_OT_paintmode_toggle";
+ if (mode == OB_MODE_GPENCIL_SCULPT)
+ return "GPENCIL_OT_sculptmode_toggle";
+ if (mode == OB_MODE_GPENCIL_WEIGHT)
+ return "GPENCIL_OT_weightmode_toggle";
return NULL;
}
@@ -85,8 +92,6 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
if (ob) {
if (mode == OB_MODE_OBJECT)
return true;
- else if (mode == OB_MODE_GPENCIL)
- return true; /* XXX: assume this is the case for now... */
switch (ob->type) {
case OB_MESH:
@@ -111,6 +116,13 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
if (mode & (OB_MODE_EDIT | OB_MODE_POSE))
return true;
break;
+ case OB_GPENCIL:
+ if (mode & (OB_MODE_EDIT | OB_MODE_GPENCIL_EDIT | OB_MODE_GPENCIL_PAINT |
+ OB_MODE_GPENCIL_SCULPT | OB_MODE_GPENCIL_WEIGHT))
+ {
+ return true;
+ }
+ break;
}
}
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 11d0fd9f9d5..f83c6af08ee 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -1,31 +1,31 @@
/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * 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) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): Blender Foundation, 2009
- *
- * ***** END GPL LICENSE BLOCK *****
- */
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* 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) 2001-2002 by NaN Holding BV.
+* All rights reserved.
+*
+* Contributor(s): Blender Foundation, 2009
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
/** \file blender/editors/object/object_modifier.c
- * \ingroup edobj
- */
+* \ingroup edobj
+*/
#include <math.h>
@@ -117,8 +117,8 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
if (type == eModifierType_ParticleSystem) {
/* don't need to worry about the new modifier's name, since that is set to the number
- * of particle systems which shouldn't have too many duplicates
- */
+ * of particle systems which shouldn't have too many duplicates
+ */
new_md = object_add_particle_system(bmain, scene, ob, name);
}
else {
@@ -182,9 +182,9 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
}
/* Return true if the object has a modifier of type 'type' other than
- * the modifier pointed to be 'exclude', otherwise returns false. */
+* the modifier pointed to be 'exclude', otherwise returns false. */
static bool object_has_modifier(const Object *ob, const ModifierData *exclude,
- ModifierType type)
+ ModifierType type)
{
ModifierData *md;
@@ -197,16 +197,16 @@ static bool object_has_modifier(const Object *ob, const ModifierData *exclude,
}
/* If the object data of 'orig_ob' has other users, run 'callback' on
- * each of them.
- *
- * If include_orig is true, the callback will run on 'orig_ob' too.
- *
- * If the callback ever returns true, iteration will stop and the
- * function value will be true. Otherwise the function returns false.
- */
+* each of them.
+*
+* If include_orig is true, the callback will run on 'orig_ob' too.
+*
+* If the callback ever returns true, iteration will stop and the
+* function value will be true. Otherwise the function returns false.
+*/
bool ED_object_iter_other(Main *bmain, Object *orig_ob, const bool include_orig,
- bool (*callback)(Object *ob, void *callback_data),
- void *callback_data)
+ bool (*callback)(Object *ob, void *callback_data),
+ void *callback_data)
{
ID *ob_data_id = orig_ob->data;
int users = ob_data_id->us;
@@ -220,10 +220,10 @@ bool ED_object_iter_other(Main *bmain, Object *orig_ob, const bool include_orig,
int totfound = include_orig ? 0 : 1;
for (ob = bmain->object.first; ob && totfound < users;
- ob = ob->id.next)
+ ob = ob->id.next)
{
if (((ob != orig_ob) || include_orig) &&
- (ob->data == orig_ob->data))
+ (ob->data == orig_ob->data))
{
if (callback(ob, callback_data))
return true;
@@ -247,8 +247,8 @@ static bool object_has_modifier_cb(Object *ob, void *data)
}
/* Use with ED_object_iter_other(). Sets the total number of levels
- * for any multires modifiers on the object to the int pointed to by
- * callback_data. */
+* for any multires modifiers on the object to the int pointed to by
+* callback_data. */
bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v)
{
ModifierData *md;
@@ -265,20 +265,20 @@ bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v)
/* Return true if no modifier of type 'type' other than 'exclude' */
static bool object_modifier_safe_to_delete(Main *bmain, Object *ob,
- ModifierData *exclude,
- ModifierType type)
+ ModifierData *exclude,
+ ModifierType type)
{
return (!object_has_modifier(ob, exclude, type) &&
- !ED_object_iter_other(bmain, ob, false,
- object_has_modifier_cb, &type));
+ !ED_object_iter_other(bmain, ob, false,
+ object_has_modifier_cb, &type));
}
static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md,
- bool *r_sort_depsgraph)
+ bool *r_sort_depsgraph)
{
/* It seems on rapid delete it is possible to
- * get called twice on same modifier, so make
- * sure it is in list. */
+ * get called twice on same modifier, so make
+ * sure it is in list. */
if (BLI_findindex(&ob->modifiers, md) == -1) {
return 0;
}
@@ -318,7 +318,7 @@ static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md,
}
if (ELEM(md->type, eModifierType_Softbody, eModifierType_Cloth) &&
- BLI_listbase_is_empty(&ob->particlesystem))
+ BLI_listbase_is_empty(&ob->particlesystem))
{
ob->mode &= ~OB_MODE_PARTICLE_EDIT;
}
@@ -522,7 +522,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
}
static int modifier_apply_shape(
- Main *bmain, ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md)
+ Main *bmain, ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
@@ -532,15 +532,15 @@ static int modifier_apply_shape(
}
/*
- * It should be ridiculously easy to extract the original verts that we want
- * and form the shape data. We can probably use the CD KEYINDEX layer (or
- * whatever I ended up calling it, too tired to check now), though this would
- * by necessity have to make some potentially ugly assumptions about the order
- * of the mesh data :-/ you can probably assume in 99% of cases that the first
- * element of a given index is the original, and any subsequent duplicates are
- * copies/interpolates, but that's an assumption that would need to be tested
- * and then predominantly stated in comments in a half dozen headers.
- */
+ * It should be ridiculously easy to extract the original verts that we want
+ * and form the shape data. We can probably use the CD KEYINDEX layer (or
+ * whatever I ended up calling it, too tired to check now), though this would
+ * by necessity have to make some potentially ugly assumptions about the order
+ * of the mesh data :-/ you can probably assume in 99% of cases that the first
+ * element of a given index is the original, and any subsequent duplicates are
+ * copies/interpolates, but that's an assumption that would need to be tested
+ * and then predominantly stated in comments in a half dozen headers.
+ */
if (ob->type == OB_MESH) {
Mesh *mesh_applied;
@@ -563,7 +563,7 @@ static int modifier_apply_shape(
key = me->key = BKE_key_add(bmain, (ID *)me);
key->type = KEY_RELATIVE;
/* if that was the first key block added, then it was the basis.
- * Initialize it with the mesh, and add another for the modifier */
+ * Initialize it with the mesh, and add another for the modifier */
kb = BKE_keyblock_add(key, NULL);
BKE_keyblock_convert_from_mesh(me, key, kb);
}
@@ -667,8 +667,8 @@ static int modifier_apply_obdata(ReportList *reports, Depsgraph *depsgraph, Scen
}
int ED_object_modifier_apply(
- Main *bmain, ReportList *reports, Depsgraph *depsgraph,
- Scene *scene, Object *ob, ModifierData *md, int mode)
+ Main *bmain, ReportList *reports, Depsgraph *depsgraph,
+ Scene *scene, Object *ob, ModifierData *md, int mode)
{
int prev_mode;
@@ -681,8 +681,8 @@ int ED_object_modifier_apply(
return 0;
}
else if ((ob->mode & OB_MODE_SCULPT) &&
- (find_multires_modifier_before(scene, md)) &&
- (modifier_isSameTopology(md) == false))
+ (find_multires_modifier_before(scene, md)) &&
+ (modifier_isSameTopology(md) == false))
{
BKE_report(reports, RPT_ERROR, "Constructive modifier cannot be applied to multi-res data in sculpt mode");
return 0;
@@ -692,7 +692,7 @@ int ED_object_modifier_apply(
BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected");
/* Get evaluated modifier, so object links pointer to evaluated data,
- * but still use original object it is applied to the original mesh. */
+ * but still use original object it is applied to the original mesh. */
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ModifierData *md_eval = (ob_eval) ? modifiers_findByName(ob_eval, md->name) : md;
@@ -752,7 +752,7 @@ static int modifier_add_exec(bContext *C, wmOperator *op)
}
static const EnumPropertyItem *modifier_add_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
Object *ob = ED_object_active_context(C);
EnumPropertyItem *item = NULL;
@@ -1165,8 +1165,8 @@ static int multires_higher_levels_delete_exec(bContext *C, wmOperator *op)
multiresModifier_del_levels(mmd, scene, ob, 1);
ED_object_iter_other(CTX_data_main(C), ob, true,
- ED_object_multires_update_totlevels_cb,
- &mmd->totlvl);
+ ED_object_multires_update_totlevels_cb,
+ &mmd->totlvl);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
@@ -1210,8 +1210,8 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op)
multiresModifier_subdivide(mmd, scene, ob, 0, mmd->simple);
ED_object_iter_other(CTX_data_main(C), ob, true,
- ED_object_multires_update_totlevels_cb,
- &mmd->totlvl);
+ ED_object_multires_update_totlevels_cb,
+ &mmd->totlvl);
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
@@ -1387,8 +1387,8 @@ void OBJECT_OT_multires_external_save(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
WM_operator_properties_filesel(
- ot, FILE_TYPE_FOLDER | FILE_TYPE_BTX, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BTX, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
edit_modifier_properties(ot);
}
@@ -1480,13 +1480,13 @@ static void modifier_skin_customdata_delete(Object *ob)
static bool skin_poll(bContext *C)
{
return (!CTX_data_edit_object(C) &&
- edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH)));
+ edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH)));
}
static bool skin_edit_poll(bContext *C)
{
return (CTX_data_edit_object(C) &&
- edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH)));
+ edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH)));
}
static void skin_root_clear(BMVert *bm_vert, GSet *visited, const int cd_vert_skin_offset)
@@ -1525,7 +1525,7 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op))
BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT) &&
- BLI_gset_add(visited, bm_vert))
+ BLI_gset_add(visited, bm_vert))
{
MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(bm_vert, cd_vert_skin_offset);
@@ -1579,8 +1579,8 @@ static int skin_loose_mark_clear_exec(bContext *C, wmOperator *op)
BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT)) {
MVertSkin *vs = CustomData_bmesh_get(&bm->vdata,
- bm_vert->head.data,
- CD_MVERT_SKIN);
+ bm_vert->head.data,
+ CD_MVERT_SKIN);
switch (action) {
@@ -1636,8 +1636,8 @@ static int skin_radii_equalize_exec(bContext *C, wmOperator *UNUSED(op))
BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT)) {
MVertSkin *vs = CustomData_bmesh_get(&bm->vdata,
- bm_vert->head.data,
- CD_MVERT_SKIN);
+ bm_vert->head.data,
+ CD_MVERT_SKIN);
float avg = (vs->radius[0] + vs->radius[1]) * 0.5f;
vs->radius[0] = vs->radius[1] = avg;
@@ -1664,12 +1664,12 @@ void OBJECT_OT_skin_radii_equalize(wmOperatorType *ot)
}
static void skin_armature_bone_create(Object *skin_ob,
- MVert *mvert, MEdge *medge,
- bArmature *arm,
- BLI_bitmap *edges_visited,
- const MeshElemMap *emap,
- EditBone *parent_bone,
- int parent_v)
+ MVert *mvert, MEdge *medge,
+ bArmature *arm,
+ BLI_bitmap *edges_visited,
+ const MeshElemMap *emap,
+ EditBone *parent_bone,
+ int parent_v)
{
int i;
@@ -1704,12 +1704,12 @@ static void skin_armature_bone_create(Object *skin_ob,
}
skin_armature_bone_create(skin_ob,
- mvert, medge,
- arm,
- edges_visited,
- emap,
- bone,
- v);
+ mvert, medge,
+ arm,
+ edges_visited,
+ emap,
+ bone,
+ v);
}
}
@@ -1731,10 +1731,10 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain,
/* add vertex weights to original mesh */
CustomData_add_layer(&me->vdata,
- CD_MDEFORMVERT,
- CD_CALLOC,
- NULL,
- me->totvert);
+ CD_MDEFORMVERT,
+ CD_CALLOC,
+ NULL,
+ me->totvert);
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
arm_ob = BKE_object_add(bmain, scene, view_layer, OB_ARMATURE, NULL);
@@ -1747,19 +1747,19 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain,
mvert_skin = CustomData_get_layer(&me->vdata, CD_MVERT_SKIN);
BKE_mesh_vert_edge_map_create(&emap, &emap_mem,
- me->medge, me->totvert, me->totedge);
+ me->medge, me->totvert, me->totedge);
edges_visited = BLI_BITMAP_NEW(me->totedge, "edge_visited");
/* note: we use EditBones here, easier to set them up and use
- * edit-armature functions to convert back to regular bones */
+ * edit-armature functions to convert back to regular bones */
for (v = 0; v < me->totvert; v++) {
if (mvert_skin[v].flag & MVERT_SKIN_ROOT) {
EditBone *bone = NULL;
/* Unless the skin root has just one adjacent edge, create
- * a fake root bone (have it going off in the Y direction
- * (arbitrary) */
+ * a fake root bone (have it going off in the Y direction
+ * (arbitrary) */
if (emap[v].count > 1) {
bone = ED_armature_ebone_add(arm, "Bone");
@@ -1772,12 +1772,12 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain,
if (emap[v].count >= 1) {
skin_armature_bone_create(skin_ob,
- mvert, me->medge,
- arm,
- edges_visited,
- emap,
- bone,
- v);
+ mvert, me->medge,
+ arm,
+ edges_visited,
+ emap,
+ bone,
+ v);
}
}
}
@@ -2092,7 +2092,7 @@ static int oceanbake_breakjob(void *UNUSED(customdata))
//return *(ob->stop);
/* this is not nice yet, need to make the jobs list template better
- * for identifying/acting upon various different jobs */
+ * for identifying/acting upon various different jobs */
/* but for now we'll reuse the render break... */
return (G.is_break);
}
@@ -2166,8 +2166,8 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
}
och = BKE_ocean_init_cache(omd->cachepath, modifier_path_relbase(bmain, ob),
- omd->bakestart, omd->bakeend, omd->wave_scale,
- omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
+ omd->bakestart, omd->bakeend, omd->wave_scale,
+ omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
och->time = MEM_mallocN(och->duration * sizeof(float), "foam bake time");
@@ -2176,22 +2176,22 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
/* precalculate time variable before baking */
for (f = omd->bakestart; f <= omd->bakeend; f++) {
/* from physics_fluid.c:
- *
- * XXX: This can't be used due to an anim sys optimization that ignores recalc object animation,
- * leaving it for the depgraph (this ignores object animation such as modifier properties though... :/ )
- * --> BKE_animsys_evaluate_all_animation(bmain, eval_time);
- * This doesn't work with drivers:
- * --> BKE_animsys_evaluate_animdata(&fsDomain->id, fsDomain->adt, eval_time, ADT_RECALC_ALL);
- */
+ *
+ * XXX: This can't be used due to an anim sys optimization that ignores recalc object animation,
+ * leaving it for the depgraph (this ignores object animation such as modifier properties though... :/ )
+ * --> BKE_animsys_evaluate_all_animation(bmain, eval_time);
+ * This doesn't work with drivers:
+ * --> BKE_animsys_evaluate_animdata(&fsDomain->id, fsDomain->adt, eval_time, ADT_RECALC_ALL);
+ */
/* Modifying the global scene isn't nice, but we can do it in
- * this part of the process before a threaded job is created */
+ * this part of the process before a threaded job is created */
//scene->r.cfra = f;
//ED_update_for_newframe(bmain, scene);
/* ok, this doesn't work with drivers, but is way faster.
- * let's use this for now and hope nobody wants to drive the time value... */
+ * let's use this for now and hope nobody wants to drive the time value... */
BKE_animsys_evaluate_animdata(CTX_data_depsgraph(C), scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM);
och->time[i] = omd->time;
@@ -2220,7 +2220,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
/* setup job */
wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Ocean Simulation",
- WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_SIM_OCEAN);
+ WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_SIM_OCEAN);
oj = MEM_callocN(sizeof(OceanBakeJob), "ocean bake job");
oj->owner = ob;
oj->ocean = ocean;
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 7b6c1156874..ac2eb60456f 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -115,6 +115,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_empty_add);
WM_operatortype_append(OBJECT_OT_lightprobe_add);
WM_operatortype_append(OBJECT_OT_drop_named_image);
+ WM_operatortype_append(OBJECT_OT_gpencil_add);
WM_operatortype_append(OBJECT_OT_light_add);
WM_operatortype_append(OBJECT_OT_camera_add);
WM_operatortype_append(OBJECT_OT_speaker_add);
@@ -147,6 +148,20 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_skin_radii_equalize);
WM_operatortype_append(OBJECT_OT_skin_armature_create);
+ /* grease pencil modifiers */
+ WM_operatortype_append(OBJECT_OT_gpencil_modifier_add);
+ WM_operatortype_append(OBJECT_OT_gpencil_modifier_remove);
+ WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_up);
+ WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_down);
+ WM_operatortype_append(OBJECT_OT_gpencil_modifier_apply);
+ WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy);
+
+ /* shader fx */
+ WM_operatortype_append(OBJECT_OT_shaderfx_add);
+ WM_operatortype_append(OBJECT_OT_shaderfx_remove);
+ WM_operatortype_append(OBJECT_OT_shaderfx_move_up);
+ WM_operatortype_append(OBJECT_OT_shaderfx_move_down);
+
WM_operatortype_append(OBJECT_OT_correctivesmooth_bind);
WM_operatortype_append(OBJECT_OT_meshdeform_bind);
WM_operatortype_append(OBJECT_OT_explode_refresh);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 331b4af077d..a6751ee12a4 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -70,6 +70,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_displist.h"
#include "BKE_global.h"
+#include "BKE_gpencil.h"
#include "BKE_fcurve.h"
#include "BKE_idprop.h"
#include "BKE_lamp.h"
@@ -1609,21 +1610,11 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
/**************************** Make Single User ********************************/
-static Object *single_object_users_object(Main *bmain, Scene *scene, Object *ob)
+static Object *single_object_users_object(Main *bmain, Object *ob)
{
/* base gets copy of object */
Object *obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob));
- /* remap gpencil parenting */
-
- if (scene->gpd) {
- bGPdata *gpd = scene->gpd;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->parent == ob) {
- gpl->parent = obn;
- }
- }
- }
id_us_plus(&obn->id);
id_us_min(&ob->id);
@@ -1648,7 +1639,7 @@ static void single_object_users_collection(Main *bmain, Scene *scene, Collection
/* an object may be in more than one collection */
if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) {
if (!ID_IS_LINKED(ob) && ob->id.us > 1) {
- cob->ob = single_object_users_object(bmain, scene, cob->ob);
+ cob->ob = single_object_users_object(bmain, cob->ob);
}
}
}
@@ -1702,6 +1693,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
/* collection pointers in scene */
BKE_scene_groups_relink(scene);
+ /* active camera */
ID_NEW_REMAP(scene->camera);
if (v3d) ID_NEW_REMAP(v3d->camera);
@@ -1805,6 +1797,9 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer
case OB_LIGHTPROBE:
ob->data = ID_NEW_SET(ob->data, BKE_lightprobe_copy(bmain, ob->data));
break;
+ case OB_GPENCIL:
+ ob->data = ID_NEW_SET(ob->data, BKE_gpencil_copy(bmain, ob->data));
+ break;
default:
printf("ERROR %s: can't copy %s\n", __func__, id->name);
BLI_assert(!"This should never happen.");
@@ -1940,10 +1935,6 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo
}
}
- if (scene->gpd) {
- IDP_RelinkProperty(scene->gpd->id.properties);
- }
-
if (scene->world) {
IDP_RelinkProperty(scene->world->id.properties);
}
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index d5f7a93cc6e..c23a1d64ee8 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -41,6 +41,7 @@
#include "DNA_armature_types.h"
#include "DNA_lamp_types.h"
#include "DNA_workspace_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -88,8 +89,8 @@
* this takes into account the 'restrict selection in 3d view' flag.
* deselect works always, the restriction just prevents selection */
-/* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! (or
- * or a NC_SCENE|ND_OB_VISIBLE in case of visibility toggling */
+ /* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! (or
+ * or a NC_SCENE|ND_OB_VISIBLE in case of visibility toggling */
void ED_object_base_select(Base *base, eObjectSelect_Mode mode)
{
diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c
new file mode 100644
index 00000000000..681851850a5
--- /dev/null
+++ b/source/blender/editors/object/object_shader_fx.c
@@ -0,0 +1,469 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2018
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/object/object_shader_fx.c
+ * \ingroup edobj
+ */
+
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_shader_fx_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_shader_fx.h"
+#include "BKE_report.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "object_intern.h"
+
+/******************************** API ****************************/
+
+ShaderFxData *ED_object_shaderfx_add(ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
+{
+ ShaderFxData *new_fx = NULL;
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type);
+
+ if (ob->type != OB_GPENCIL) {
+ BKE_reportf(reports, RPT_WARNING, "Effect cannot be added to object '%s'", ob->id.name + 2);
+ return NULL;
+ }
+
+ if (fxi->flags & eShaderFxTypeFlag_Single) {
+ if (BKE_shaderfx_findByType(ob, type)) {
+ BKE_report(reports, RPT_WARNING, "Only one Effect of this type is allowed");
+ return NULL;
+ }
+ }
+
+ /* get new effect data to add */
+ new_fx = BKE_shaderfx_new(type);
+
+ BLI_addtail(&ob->shader_fx, new_fx);
+
+ if (name) {
+ BLI_strncpy_utf8(new_fx->name, name, sizeof(new_fx->name));
+ }
+
+ /* make sure effect data has unique name */
+ BKE_shaderfx_unique_name(&ob->shader_fx, new_fx);
+
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+
+ return new_fx;
+}
+
+/* Return true if the object has a effect of type 'type' other than
+ * the shaderfx pointed to be 'exclude', otherwise returns false. */
+static bool UNUSED_FUNCTION(object_has_shaderfx)(
+ const Object *ob, const ShaderFxData *exclude,
+ ShaderFxType type)
+{
+ ShaderFxData *fx;
+
+ for (fx = ob->shader_fx.first; fx; fx = fx->next) {
+ if ((fx != exclude) && (fx->type == type))
+ return true;
+ }
+
+ return false;
+}
+
+static bool object_shaderfx_remove(
+ Main *bmain, Object *ob, ShaderFxData *fx,
+ bool *UNUSED(r_sort_depsgraph))
+{
+ /* It seems on rapid delete it is possible to
+ * get called twice on same effect, so make
+ * sure it is in list. */
+ if (BLI_findindex(&ob->shader_fx, fx) == -1) {
+ return 0;
+ }
+
+ DEG_relations_tag_update(bmain);
+
+ BLI_remlink(&ob->shader_fx, fx);
+ BKE_shaderfx_free(fx);
+ BKE_object_free_derived_caches(ob);
+
+ return 1;
+}
+
+bool ED_object_shaderfx_remove(ReportList *reports, Main *bmain, Object *ob, ShaderFxData *fx)
+{
+ bool sort_depsgraph = false;
+ bool ok;
+
+ ok = object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph);
+
+ if (!ok) {
+ BKE_reportf(reports, RPT_ERROR, "Effect '%s' not in object '%s'", fx->name, ob->id.name);
+ return 0;
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+
+ return 1;
+}
+
+void ED_object_shaderfx_clear(Main *bmain, Object *ob)
+{
+ ShaderFxData *fx = ob->shader_fx.first;
+ bool sort_depsgraph = false;
+
+ if (!fx)
+ return;
+
+ while (fx) {
+ ShaderFxData *next_fx;
+
+ next_fx = fx->next;
+
+ object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph);
+
+ fx = next_fx;
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+}
+
+int ED_object_shaderfx_move_up(ReportList *UNUSED(reports), Object *ob, ShaderFxData *fx)
+{
+ if (fx->prev) {
+ BLI_remlink(&ob->shader_fx, fx);
+ BLI_insertlinkbefore(&ob->shader_fx, fx->prev, fx);
+ }
+
+ return 1;
+}
+
+int ED_object_shaderfx_move_down(ReportList *UNUSED(reports), Object *ob, ShaderFxData *fx)
+{
+ if (fx->next) {
+ BLI_remlink(&ob->shader_fx, fx);
+ BLI_insertlinkafter(&ob->shader_fx, fx->next, fx);
+ }
+
+ return 1;
+}
+
+/************************ add effect operator *********************/
+
+static int shaderfx_add_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = ED_object_active_context(C);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ if (!ED_object_shaderfx_add(op->reports, bmain, scene, ob, NULL, type))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static const EnumPropertyItem *shaderfx_add_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ Object *ob = ED_object_active_context(C);
+ EnumPropertyItem *item = NULL;
+ const EnumPropertyItem *fx_item, *group_item = NULL;
+ const ShaderFxTypeInfo *mti;
+ int totitem = 0, a;
+
+ if (!ob)
+ return rna_enum_object_shaderfx_type_items;
+
+ for (a = 0; rna_enum_object_shaderfx_type_items[a].identifier; a++) {
+ fx_item = &rna_enum_object_shaderfx_type_items[a];
+ if (fx_item->identifier[0]) {
+ mti = BKE_shaderfxType_getInfo(fx_item->value);
+
+ if (mti->flags & eShaderFxTypeFlag_NoUserAdd)
+ continue;
+ }
+ else {
+ group_item = fx_item;
+ fx_item = NULL;
+
+ continue;
+ }
+
+ if (group_item) {
+ RNA_enum_item_add(&item, &totitem, group_item);
+ group_item = NULL;
+ }
+
+ RNA_enum_item_add(&item, &totitem, fx_item);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+void OBJECT_OT_shaderfx_add(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Add Effect";
+ ot->description = "Add a visual effect to the active object";
+ ot->idname = "OBJECT_OT_shaderfx_add";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = shaderfx_add_exec;
+ ot->poll = ED_operator_object_active_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "type", rna_enum_object_shaderfx_type_items, eShaderFxType_Blur, "Type", "");
+ RNA_def_enum_funcs(prop, shaderfx_add_itemf);
+ ot->prop = prop;
+}
+
+/************************ generic functions for operators using names and data context *********************/
+
+static bool edit_shaderfx_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag)
+{
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", rna_type);
+ Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C);
+
+ if (!ptr.data) {
+ CTX_wm_operator_poll_msg_set(C, "Context missing 'shaderfx'");
+ return 0;
+ }
+
+ if (!ob || ID_IS_LINKED(ob)) return 0;
+ if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0;
+ if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) return 0;
+
+ if (ID_IS_STATIC_OVERRIDE(ob)) {
+ CTX_wm_operator_poll_msg_set(C, "Cannot edit shaderfxs comming from static override");
+ return (((ShaderFxData *)ptr.data)->flag & eShaderFxFlag_StaticOverride_Local) != 0;
+ }
+
+ return 1;
+}
+
+static bool edit_shaderfx_poll(bContext *C)
+{
+ return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0);
+}
+
+static void edit_shaderfx_properties(wmOperatorType *ot)
+{
+ RNA_def_string(ot->srna, "shaderfx", NULL, MAX_NAME, "Shader", "Name of the shaderfx to edit");
+}
+
+static int edit_shaderfx_invoke_properties(bContext *C, wmOperator *op)
+{
+ ShaderFxData *fx;
+
+ if (RNA_struct_property_is_set(op->ptr, "shaderfx")) {
+ return true;
+ }
+ else {
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", &RNA_ShaderFx);
+ if (ptr.data) {
+ fx = ptr.data;
+ RNA_string_set(op->ptr, "shaderfx", fx->name);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static ShaderFxData *edit_shaderfx_property_get(wmOperator *op, Object *ob, int type)
+{
+ char shaderfx_name[MAX_NAME];
+ ShaderFxData *fx;
+ RNA_string_get(op->ptr, "shaderfx", shaderfx_name);
+
+ fx = BKE_shaderfx_findByName(ob, shaderfx_name);
+
+ if (fx && type != 0 && fx->type != type)
+ fx = NULL;
+
+ return fx;
+}
+
+/************************ remove shaderfx operator *********************/
+
+static int shaderfx_remove_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = ED_object_active_context(C);
+ ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
+
+ if (!fx || !ED_object_shaderfx_remove(op->reports, bmain, ob, fx))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int shaderfx_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_shaderfx_invoke_properties(C, op))
+ return shaderfx_remove_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_shaderfx_remove(wmOperatorType *ot)
+{
+ ot->name = "Remove Grease Pencil Modifier";
+ ot->description = "Remove a shaderfx from the active grease pencil object";
+ ot->idname = "OBJECT_OT_shaderfx_remove";
+
+ ot->invoke = shaderfx_remove_invoke;
+ ot->exec = shaderfx_remove_exec;
+ ot->poll = edit_shaderfx_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_shaderfx_properties(ot);
+}
+
+/************************ move up shaderfx operator *********************/
+
+static int shaderfx_move_up_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
+
+ if (!fx || !ED_object_shaderfx_move_up(op->reports, ob, fx))
+ return OPERATOR_CANCELLED;
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int shaderfx_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_shaderfx_invoke_properties(C, op))
+ return shaderfx_move_up_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_shaderfx_move_up(wmOperatorType *ot)
+{
+ ot->name = "Move Up Modifier";
+ ot->description = "Move shaderfx up in the stack";
+ ot->idname = "OBJECT_OT_shaderfx_move_up";
+
+ ot->invoke = shaderfx_move_up_invoke;
+ ot->exec = shaderfx_move_up_exec;
+ ot->poll = edit_shaderfx_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_shaderfx_properties(ot);
+}
+
+/************************ move down shaderfx operator *********************/
+
+static int shaderfx_move_down_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
+
+ if (!fx || !ED_object_shaderfx_move_down(op->reports, ob, fx))
+ return OPERATOR_CANCELLED;
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int shaderfx_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_shaderfx_invoke_properties(C, op))
+ return shaderfx_move_down_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_shaderfx_move_down(wmOperatorType *ot)
+{
+ ot->name = "Move Down Modifier";
+ ot->description = "Move shaderfx down in the stack";
+ ot->idname = "OBJECT_OT_shaderfx_move_down";
+
+ ot->invoke = shaderfx_move_down_invoke;
+ ot->exec = shaderfx_move_down_exec;
+ ot->poll = edit_shaderfx_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_shaderfx_properties(ot);
+}
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index d2a0879464b..96b540251b4 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -38,6 +38,7 @@
#include "DNA_lamp_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_lattice_types.h"
@@ -59,6 +60,7 @@
#include "BKE_armature.h"
#include "BKE_lattice.h"
#include "BKE_tracking.h"
+#include "BKE_gpencil.h"
#include "DEG_depsgraph.h"
@@ -73,6 +75,7 @@
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "ED_gpencil.h"
#include "MEM_guardedalloc.h"
@@ -434,7 +437,7 @@ static int apply_objects_internal(
/* first check if we can execute */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
- if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT)) {
+ if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT, OB_GPENCIL)) {
ID *obdata = ob->data;
if (ID_REAL_USERS(obdata) > 1) {
BKE_reportf(reports, RPT_ERROR,
@@ -480,6 +483,37 @@ static int apply_objects_internal(
}
}
+ if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = ob->data;
+ if (gpd) {
+ if (gpd->layers.first) {
+ /* Unsupported configuration */
+ bool has_unparented_layers = false;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* Parented layers aren't supported as we can't easily re-evaluate the scene to sample parent movement */
+ if (gpl->parent == NULL) {
+ has_unparented_layers = true;
+ break;
+ }
+ }
+
+ if (has_unparented_layers == false) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Can't apply to a GP datablock where all layers are parented: Object \"%s\", %s \"%s\", aborting",
+ ob->id.name + 2, BKE_idcode_to_name(ID_GD), gpd->id.name + 2);
+ changed = false;
+ }
+ }
+ else {
+ /* No layers/data */
+ BKE_reportf(reports, RPT_ERROR,
+ "Can't apply to GP datablock with no layers: Object \"%s\", %s \"%s\", aborting",
+ ob->id.name + 2, BKE_idcode_to_name(ID_GD), gpd->id.name + 2);
+ }
+ }
+ }
+
if (ob->type == OB_LAMP) {
Lamp *la = ob->data;
if (la->type == LA_AREA) {
@@ -587,6 +621,10 @@ static int apply_objects_internal(
cu->fsize *= scale;
}
}
+ else if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = ob->data;
+ BKE_gpencil_transform(gpd, mat);
+ }
else if (ob->type == OB_CAMERA) {
MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
@@ -1056,6 +1094,69 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
lt->id.tag |= LIB_TAG_DOIT;
do_inverse_offset = true;
}
+ else if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = ob->data;
+ float gpcenter[3];
+ if (gpd) {
+ if (centermode == ORIGIN_TO_GEOMETRY) {
+ zero_v3(gpcenter);
+ BKE_gpencil_centroid_3D(gpd, gpcenter);
+ add_v3_v3(gpcenter, ob->obmat[3]);
+ }
+ if (centermode == ORIGIN_TO_CURSOR) {
+ copy_v3_v3(gpcenter, cursor);
+ }
+ if ((centermode == ORIGIN_TO_GEOMETRY) || (centermode == ORIGIN_TO_CURSOR)) {
+ bGPDspoint *pt;
+ float imat[3][3], bmat[3][3];
+ float offset_global[3];
+ float offset_local[3];
+ int i;
+
+ sub_v3_v3v3(offset_global, gpcenter, ob->obmat[3]);
+ copy_m3_m4(bmat, obact->obmat);
+ invert_m3_m3(imat, bmat);
+ mul_m3_v3(imat, offset_global);
+ mul_v3_m3v3(offset_local, imat, offset_global);
+
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+
+ /* recalculate all strokes (all layers are considered without evaluating lock attributtes) */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, 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) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float mpt[3];
+ mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
+ sub_v3_v3(mpt, offset_local);
+ mul_v3_m4v3(&pt->x, diff_mat, mpt);
+ }
+ }
+ }
+ }
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ tot_change++;
+ if (centermode == ORIGIN_TO_GEOMETRY) {
+ copy_v3_v3(ob->loc, gpcenter);
+ }
+ ob->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "Grease Pencil Object does not support this set origin option");
+ }
+ }
+ }
/* offset other selected objects */
if (do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) {
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 22000bd2a03..ed7950f3993 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -329,7 +329,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
GPU_matrix_translate_2f(sizex / 2, sizey / 2);
G.f |= G_RENDER_OGL;
- ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
+ ED_gpencil_draw_ex(rv3d, scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
G.f &= ~G_RENDER_OGL;
gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
@@ -417,7 +417,7 @@ static void screen_opengl_render_write(OGLRender *oglrender)
else printf("OpenGL Render failed to write '%s'\n", name);
}
-static void addAlphaOverFloat(float dest[4], const float source[4])
+static void UNUSED_FUNCTION(addAlphaOverFloat)(float dest[4], const float source[4])
{
/* d = s + (1-alpha_s)d*/
float mul;
@@ -431,91 +431,6 @@ static void addAlphaOverFloat(float dest[4], const float source[4])
}
-/* add renderlayer and renderpass for each grease pencil layer for using in composition */
-static void add_gpencil_renderpass(const bContext *C, OGLRender *oglrender, RenderResult *rr, RenderView *rv)
-{
- bGPdata *gpd = oglrender->scene->gpd;
- Scene *scene = oglrender->scene;
-
- /* sanity checks */
- if (gpd == NULL) {
- return;
- }
- if (scene == NULL) {
- return;
- }
- if (BLI_listbase_is_empty(&gpd->layers)) {
- return;
- }
- if (oglrender->v3d != NULL && (oglrender->v3d->flag2 & V3D_SHOW_GPENCIL) == 0) {
- return;
- }
-
- /* save old alpha mode */
- short oldalphamode = scene->r.alphamode;
- /* set alpha transparent for gp */
- scene->r.alphamode = R_ALPHAPREMUL;
-
- /* saves layer status */
- short *oldsts = MEM_mallocN(BLI_listbase_count(&gpd->layers) * sizeof(short), "temp_gplayers_flag");
- int i = 0;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- oldsts[i] = gpl->flag;
- ++i;
- }
- /* loop all layers to create separate render */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* dont draw layer if hidden */
- if (gpl->flag & GP_LAYER_HIDE)
- continue;
- /* hide all layer except current */
- for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) {
- if (gpl != gph) {
- gph->flag |= GP_LAYER_HIDE;
- }
- }
-
- /* render this gp layer */
- screen_opengl_render_doit(C, oglrender, rr);
-
- /* add RendePass composite */
- RenderPass *rp = RE_create_gp_pass(rr, gpl->info, rv->name);
-
- /* copy image data from rectf */
- // XXX: Needs conversion.
- unsigned char *src = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
- if (src != NULL) {
- float *dest = rp->rect;
-
- int x, y, rectx, recty;
- rectx = rr->rectx;
- recty = rr->recty;
- for (y = 0; y < recty; y++) {
- for (x = 0; x < rectx; x++) {
- unsigned char *pixSrc = src + 4 * (rectx * y + x);
- if (pixSrc[3] > 0) {
- float *pixDest = dest + 4 * (rectx * y + x);
- float float_src[4];
- srgb_to_linearrgb_uchar4(float_src, pixSrc);
- addAlphaOverFloat(pixDest, float_src);
- }
- }
- }
- }
- /* back layer status */
- i = 0;
- for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) {
- gph->flag = oldsts[i];
- ++i;
- }
- }
- /* free memory */
- MEM_freeN(oldsts);
-
- /* back default alpha mode */
- scene->r.alphamode = oldalphamode;
-}
-
static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
{
RenderResult *rr;
@@ -550,11 +465,6 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
BLI_assert(view_id < oglrender->views_len);
RE_SetActiveRenderView(oglrender->re, rv->name);
oglrender->view_id = view_id;
- /* add grease pencil passes. For sequencer, the render does not include renderpasses
- * TODO: The sequencer render of grease pencil should be rethought */
- if (!oglrender->is_sequencer) {
- add_gpencil_renderpass(C, oglrender, rr, rv);
- }
/* render composite */
screen_opengl_render_doit(C, oglrender, rr);
}
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 3423eedf7ca..069611be35d 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -198,6 +198,7 @@ typedef struct IconPreview {
static Main *G_pr_main = NULL;
static Main *G_pr_main_cycles = NULL;
+static Main *G_pr_main_grease_pencil = NULL;
#ifndef WITH_HEADLESS
static Main *load_main_from_memory(const void *blend, int blend_size)
@@ -227,6 +228,7 @@ void ED_preview_ensure_dbase(void)
if (!base_initialized) {
G_pr_main = load_main_from_memory(datatoc_preview_blend, datatoc_preview_blend_size);
G_pr_main_cycles = load_main_from_memory(datatoc_preview_cycles_blend, datatoc_preview_cycles_blend_size);
+ G_pr_main_grease_pencil = load_main_from_memory(datatoc_preview_grease_pencil_blend, datatoc_preview_grease_pencil_blend_size);
base_initialized = true;
}
#endif
@@ -245,6 +247,9 @@ void ED_preview_free_dbase(void)
if (G_pr_main_cycles)
BKE_main_free(G_pr_main_cycles);
+
+ if (G_pr_main_grease_pencil)
+ BKE_main_free(G_pr_main_grease_pencil);
}
static Scene *preview_get_scene(Main *pr_main)
@@ -1102,6 +1107,7 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short
sp->id_copy = ip->id_copy;
sp->bmain = ip->bmain;
sp->own_id_copy = false;
+ Material *ma = NULL;
if (is_render) {
BLI_assert(ip->id);
@@ -1109,10 +1115,22 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short
* so don't even think of using cycle's bmain for
* texture icons
*/
- if (GS(ip->id->name) != ID_TE)
- sp->pr_main = G_pr_main_cycles;
- else
+ if (GS(ip->id->name) != ID_TE) {
+ /* grease pencil use its own preview file */
+ if (GS(ip->id->name) == ID_MA) {
+ ma = (Material *)ip->id;
+ }
+
+ if ((ma == NULL) || (ma->gp_style == NULL)) {
+ sp->pr_main = G_pr_main_cycles;
+ }
+ else {
+ sp->pr_main = G_pr_main_grease_pencil;
+ }
+ }
+ else {
sp->pr_main = G_pr_main;
+ }
}
common_preview_startjob(sp, stop, do_update, progress);
@@ -1274,11 +1292,23 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
sp->parent = parent;
sp->slot = slot;
sp->bmain = CTX_data_main(C);
+ Material *ma = NULL;
/* hardcoded preview .blend for Eevee + Cycles, this should be solved
* once with custom preview .blend path for external engines */
if ((method != PR_NODE_RENDER) && id_type != ID_TE) {
- sp->pr_main = G_pr_main_cycles;
+ /* grease pencil use its own preview file */
+ if (GS(id->name) == ID_MA) {
+ ma = (Material *)id;
+ }
+
+ if ((ma == NULL) || (ma->gp_style == NULL)) {
+ sp->pr_main = G_pr_main_cycles;
+ }
+ else {
+ sp->pr_main = G_pr_main_grease_pencil;
+ }
+
}
else {
sp->pr_main = G_pr_main;
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 8077079a9b5..2dd4f328d06 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -469,6 +469,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
{
Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -477,7 +478,12 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
ma = BKE_material_copy(bmain, ma);
}
else {
- ma = BKE_material_add(bmain, DATA_("Material"));
+ if ((!ob) || (ob->type != OB_GPENCIL)) {
+ ma = BKE_material_add(bmain, DATA_("Material"));
+ }
+ else {
+ ma = BKE_material_add_gpencil(bmain, DATA_("Material"));
+ }
ED_node_shader_default(C, &ma->id);
ma->use_nodes = true;
}
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 1a63bc1cd53..18bacee98b9 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1428,18 +1428,32 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand
}
if (flag & ED_KEYMAP_GPENCIL) {
/* grease pencil */
- /* NOTE: This is now 2 keymaps - One for basic functionality,
- * and one that only applies when "Edit Mode" is enabled
- * for strokes.
+ /* NOTE: This is now 4 keymaps - One for basic functionality,
+ * and others for special stroke modes (edit, paint and sculpt).
*
- * For now, it's easier to just include both,
- * since you hardly want one without the other.
+ * For now, it's easier to just include all,
+ * since you hardly want one without the others.
*/
wmKeyMap *keymap_general = WM_keymap_find(wm->defaultconf, "Grease Pencil", 0, 0);
- wmKeyMap *keymap_edit = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Edit Mode", 0, 0);
-
WM_event_add_keymap_handler(handlers, keymap_general);
+
+ wmKeyMap *keymap_edit = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Edit Mode", 0, 0);
WM_event_add_keymap_handler(handlers, keymap_edit);
+
+ wmKeyMap *keymap_paint = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Paint Mode", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_paint);
+
+ wmKeyMap *keymap_paint_draw = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Paint (Draw brush)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_paint_draw);
+
+ wmKeyMap *keymap_paint_erase = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Paint (Erase)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_paint_erase);
+
+ wmKeyMap *keymap_paint_fill = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Paint (Fill)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_paint_fill);
+
+ wmKeyMap *keymap_sculpt = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Sculpt Mode", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_sculpt);
}
if (flag & ED_KEYMAP_HEADER) {
/* standard keymap for headers regions */
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 17b1af29010..ecfc9f2cca0 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -34,6 +34,7 @@
#include "DNA_object_types.h"
#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_sequence_types.h"
#include "DNA_scene_types.h"
@@ -44,10 +45,13 @@
#include "BLI_utildefines.h"
+#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_paint.h"
+#include "BKE_main.h"
#include "BKE_gpencil.h"
#include "BKE_layer.h"
#include "BKE_screen.h"
@@ -80,8 +84,7 @@ const char *screen_context_dir[] = {
"sequences", "selected_sequences", "selected_editable_sequences", /* sequencer */
"gpencil_data", "gpencil_data_owner", /* grease pencil data */
"visible_gpencil_layers", "editable_gpencil_layers", "editable_gpencil_strokes",
- "active_gpencil_layer", "active_gpencil_frame", "active_gpencil_palette",
- "active_gpencil_palettecolor", "active_gpencil_brush",
+ "active_gpencil_layer", "active_gpencil_frame", "active_gpencil_brush",
"active_operator", "selected_editable_fcurves",
NULL};
@@ -467,7 +470,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
* (as outlined above - see Campbell's #ifdefs). That causes the get_active function to fail when
* called from context. For that reason, we end up using an alternative where we pass everything in!
*/
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
if (gpd) {
CTX_data_id_pointer_set(result, &gpd->id);
@@ -482,7 +485,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
PointerRNA ptr;
/* get pointer to Grease Pencil Data */
- gpd_ptr = ED_gpencil_data_get_pointers_direct((ID *)sc, scene, sa, obact, &ptr);
+ gpd_ptr = ED_gpencil_data_get_pointers_direct((ID *)sc, sa, scene, obact, &ptr);
if (gpd_ptr) {
CTX_data_pointer_set(result, ptr.id.data, ptr.type, ptr.data);
@@ -491,7 +494,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "active_gpencil_layer")) {
/* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
@@ -502,47 +505,17 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
}
- else if (CTX_data_equals(member, "active_gpencil_palette")) {
- /* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
-
- if (gpd) {
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
-
- if (palette) {
- CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilPalette, palette);
- return 1;
- }
- }
- }
- else if (CTX_data_equals(member, "active_gpencil_palettecolor")) {
- /* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
-
- if (gpd) {
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
-
- if (palette) {
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
- if (palcolor) {
- CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilPaletteColor, palcolor);
- return 1;
- }
- }
- }
- }
else if (CTX_data_equals(member, "active_gpencil_brush")) {
- /* XXX: see comment for gpencil_data case... */
- bGPDbrush *brush = BKE_gpencil_brush_getactive(scene->toolsettings);
+ Brush *brush = BKE_brush_getactive_gpencil(scene->toolsettings);
if (brush) {
- CTX_data_pointer_set(result, &scene->id, &RNA_GPencilBrush, brush);
+ CTX_data_pointer_set(result, &scene->id, &RNA_Brush, brush);
return 1;
}
}
else if (CTX_data_equals(member, "active_gpencil_frame")) {
/* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
@@ -555,7 +528,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "visible_gpencil_layers")) {
/* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
if (gpd) {
bGPDlayer *gpl;
@@ -571,7 +544,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "editable_gpencil_layers")) {
/* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
if (gpd) {
bGPDlayer *gpl;
@@ -587,24 +560,37 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "editable_gpencil_strokes")) {
/* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
+ bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
if (gpd) {
bGPDlayer *gpl;
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
if (gpencil_layer_is_editable(gpl) && (gpl->actframe)) {
- bGPDframe *gpf = gpl->actframe;
+ bGPDframe *gpf;
bGPDstroke *gps;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use_direct(sa, gps)) {
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
- continue;
+ for (gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use_direct(sa, gps)) {
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ continue;
+ }
+
+ CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps);
+ }
}
-
- CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps);
+ }
+ /* if not multiedit out of loop */
+ if (!is_multiedit) {
+ break;
}
}
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index a837b32b0bb..df909794353 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -2608,11 +2608,14 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
/* populate tree with keyframe nodes */
scene_to_keylist(&ads, scene, &keys, NULL);
- gpencil_to_keylist(&ads, scene->gpd, &keys);
if (ob) {
ob_to_keylist(&ads, ob, &keys, NULL);
- gpencil_to_keylist(&ads, ob->gpd, &keys);
+
+ if (ob->type == OB_GPENCIL) {
+ const bool active = !(scene->flag & SCE_KEYS_NO_SELONLY);
+ gpencil_to_keylist(&ads, ob->data, &keys, active);
+ }
}
{
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 0f796020d9e..86d36ade477 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -29,20 +29,27 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
+#include "BLI_math_color.h"
#include "DNA_customdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_paint.h"
+#include "BKE_gpencil.h"
#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "DEG_depsgraph.h"
#include "ED_paint.h"
#include "ED_screen.h"
#include "ED_image.h"
+#include "ED_gpencil.h"
#include "UI_resources.h"
#include "WM_api.h"
@@ -96,6 +103,43 @@ static void BRUSH_OT_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static int brush_add_gpencil_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ /*int type = RNA_enum_get(op->ptr, "type");*/
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Paint *paint = &ts->gp_paint->paint;
+ Brush *br = BKE_paint_brush(paint);
+ Main *bmain = CTX_data_main(C);
+ // ePaintMode mode = ePaintGpencil;
+
+ if (br) {
+ br = BKE_brush_copy(bmain, br);
+ }
+ else {
+ br = BKE_brush_add(bmain, "Brush", OB_MODE_GPENCIL_PAINT);
+ id_us_min(&br->id); /* fake user only */
+ }
+
+ BKE_paint_brush_set(paint, br);
+
+ /* TODO init grease pencil specific data */
+
+ return OPERATOR_FINISHED;
+}
+
+static void BRUSH_OT_add_gpencil(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Drawing Brush";
+ ot->description = "Add brush for grease pencil";
+ ot->idname = "BRUSH_OT_add_gpencil";
+
+ /* api callbacks */
+ ot->exec = brush_add_gpencil_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
static int brush_scale_size_exec(bContext *C, wmOperator *op)
{
@@ -232,7 +276,6 @@ static void PALETTE_OT_color_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
static int palette_color_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Paint *paint = BKE_paint_get_active_from_context(C);
@@ -1031,6 +1074,7 @@ void ED_operatortypes_paint(void)
/* brush */
WM_operatortype_append(BRUSH_OT_add);
+ WM_operatortype_append(BRUSH_OT_add_gpencil);
WM_operatortype_append(BRUSH_OT_scale_size);
WM_operatortype_append(BRUSH_OT_curve_preset);
WM_operatortype_append(BRUSH_OT_reset);
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index c46d0fdb035..831c461538a 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -51,6 +51,7 @@
#include "BKE_fcurve.h"
#include "BKE_nla.h"
#include "BKE_context.h"
+#include "BKE_gpencil.h"
#include "UI_view2d.h"
@@ -134,15 +135,20 @@ static void deselect_action_keys(bAnimContext *ac, short test, short sel)
/* Now set the flags */
for (ale = anim_data.first; ale; ale = ale->next) {
- if (ale->type == ANIMTYPE_GPLAYER)
+ if (ale->type == ANIMTYPE_GPLAYER) {
ED_gplayer_frame_select_set(ale->data, sel);
- else if (ale->type == ANIMTYPE_MASKLAYER)
+ ale->update |= ANIM_UPDATE_DEPS;
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_masklayer_frame_select_set(ale->data, sel);
- else
+ }
+ else {
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, sel_cb, NULL);
+ }
}
/* Cleanup */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -283,12 +289,16 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
ED_gplayer_frames_select_border(gpl, rectf.xmin, rectf.xmax, selectmode);
}
+ ale->update |= ANIM_UPDATE_DEPS;
break;
}
#endif
case ANIMTYPE_GPLAYER:
+ {
ED_gplayer_frames_select_border(ale->data, rectf.xmin, rectf.xmax, selectmode);
+ ale->update |= ANIM_UPDATE_DEPS;
break;
+ }
case ANIMTYPE_MASKDATABLOCK:
{
Mask *mask = ale->data;
@@ -312,6 +322,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
}
/* cleanup */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -493,6 +504,7 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view,
case ANIMTYPE_GPLAYER:
{
ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ ale->update |= ANIM_UPDATE_DEPS;
break;
}
case ANIMTYPE_MASKDATABLOCK:
@@ -520,6 +532,7 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view,
}
/* cleanup */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -707,6 +720,7 @@ static void markers_selectkeys_between(bAnimContext *ac)
}
else if (ale->type == ANIMTYPE_GPLAYER) {
ED_gplayer_frames_select_border(ale->data, min, max, SELECT_ADD);
+ ale->update |= ANIM_UPDATE_DEPS;
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_masklayer_frames_select_border(ale->data, min, max, SELECT_ADD);
@@ -717,6 +731,7 @@ static void markers_selectkeys_between(bAnimContext *ac)
}
/* Cleanup */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -796,17 +811,23 @@ static void columnselect_action_keys(bAnimContext *ac, short mode)
ked.f1 = ce->cfra;
/* select elements with frame number matching cfraelem */
- if (ale->type == ANIMTYPE_GPLAYER)
+ if (ale->type == ANIMTYPE_GPLAYER) {
ED_gpencil_select_frame(ale->data, ce->cfra, SELECT_ADD);
- else if (ale->type == ANIMTYPE_MASKLAYER)
+ ale->update |= ANIM_UPDATE_DEPS;
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_mask_select_frame(ale->data, ce->cfra, SELECT_ADD);
- else
+ }
+ else {
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ }
}
}
/* free elements */
BLI_freelistN(&ked.list);
+
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -1081,12 +1102,16 @@ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short se
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
- else if (ale->type == ANIMTYPE_GPLAYER)
+ else if (ale->type == ANIMTYPE_GPLAYER) {
ED_gplayer_frames_select_border(ale->data, ked.f1, ked.f2, select_mode);
- else if (ale->type == ANIMTYPE_MASKLAYER)
+ ale->update |= ANIM_UPDATE_DEPS;
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_masklayer_frames_select_border(ale->data, ked.f1, ked.f2, select_mode);
- else
+ }
+ else {
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ }
}
/* Sync marker support */
@@ -1111,6 +1136,7 @@ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short se
}
/* Cleanup */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -1227,6 +1253,7 @@ static void actkeys_mselect_single(bAnimContext *ac, bAnimListElem *ale, short s
/* select the nominated keyframe on the given frame */
if (ale->type == ANIMTYPE_GPLAYER) {
ED_gpencil_select_frame(ale->data, selx, select_mode);
+ ale->update |= ANIM_UPDATE_DEPS;
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_mask_select_frame(ale->data, selx, select_mode);
@@ -1244,12 +1271,14 @@ static void actkeys_mselect_single(bAnimContext *ac, bAnimListElem *ale, short s
for (ale = anim_data.first; ale; ale = ale->next) {
if (ale->type == ANIMTYPE_GPLAYER) {
ED_gpencil_select_frame(ale->data, selx, select_mode);
+ ale->update |= ANIM_UPDATE_DEPS;
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_mask_select_frame(ale->data, selx, select_mode);
}
}
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
else {
@@ -1294,16 +1323,22 @@ static void actkeys_mselect_column(bAnimContext *ac, short select_mode, float se
ked.f1 = selx;
/* select elements with frame number matching cfra */
- if (ale->type == ANIMTYPE_GPLAYER)
+ if (ale->type == ANIMTYPE_GPLAYER) {
ED_gpencil_select_frame(ale->key_data, selx, select_mode);
- else if (ale->type == ANIMTYPE_MASKLAYER)
+ ale->update |= ANIM_UPDATE_DEPS;
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_mask_select_frame(ale->key_data, selx, select_mode);
- else
+ }
+ else {
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ }
}
/* free elements */
BLI_freelistN(&ked.list);
+
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -1318,6 +1353,7 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s
/* select all keyframes in this channel */
if (ale->type == ANIMTYPE_GPLAYER) {
ED_gpencil_select_frames(ale->data, select_mode);
+ ale->update = ANIM_UPDATE_DEPS;
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_mask_select_frames(ale->data, select_mode);
@@ -1335,12 +1371,14 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s
for (ale = anim_data.first; ale; ale = ale->next) {
if (ale->type == ANIMTYPE_GPLAYER) {
ED_gpencil_select_frames(ale->data, select_mode);
+ ale->update |= ANIM_UPDATE_DEPS;
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_mask_select_frames(ale->data, select_mode);
}
}
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
else {
@@ -1473,6 +1511,7 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
/* remove active channel from list of channels for separate treatment (since it's needed later on) */
BLI_remlink(&anim_data, ale);
+ ale->next = ale->prev = NULL;
/* cleanup temporary lists */
BLI_dlrbTree_free(&anim_keys);
@@ -1557,6 +1596,12 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
}
}
+ /* flush tagged updates
+ * NOTE: We temporarily add this channel back to the list so that this can happen
+ */
+ anim_data.first = anim_data.last = ale;
+ ANIM_animdata_update(ac, &anim_data);
+
/* free this channel */
MEM_freeN(ale);
}
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index faee9c2b7ac..67632f6a53a 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -237,6 +237,7 @@ static int buttons_context_path_data(ButsContextPath *path, int type)
else if (RNA_struct_is_a(ptr->type, &RNA_Light) && (type == -1 || type == OB_LAMP)) return 1;
else if (RNA_struct_is_a(ptr->type, &RNA_Speaker) && (type == -1 || type == OB_SPEAKER)) return 1;
else if (RNA_struct_is_a(ptr->type, &RNA_LightProbe) && (type == -1 || type == OB_LIGHTPROBE)) return 1;
+ else if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && (type == -1 || type == OB_GPENCIL)) return 1;
/* try to get an object in the path, no pinning supported here */
else if (buttons_context_path_object(path)) {
ob = path->ptr[path->len - 1].data;
@@ -260,7 +261,21 @@ static int buttons_context_path_modifier(ButsContextPath *path)
if (buttons_context_path_object(path)) {
ob = path->ptr[path->len - 1].data;
- if (ob && ELEM(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE))
+ if (ob && ELEM(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE, OB_GPENCIL))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int buttons_context_path_shaderfx(ButsContextPath *path)
+{
+ Object *ob;
+
+ if (buttons_context_path_object(path)) {
+ ob = path->ptr[path->len - 1].data;
+
+ if (ob && ELEM(ob->type, OB_GPENCIL))
return 1;
}
@@ -485,6 +500,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
WorkSpace *workspace = CTX_wm_workspace(C);
ID *id;
int found;
+ Object *ob = CTX_data_active_object(C);
memset(path, 0, sizeof(*path));
path->flag = flag;
@@ -546,6 +562,9 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
case BCONTEXT_MODIFIER:
found = buttons_context_path_modifier(path);
break;
+ case BCONTEXT_SHADERFX:
+ found = buttons_context_path_shaderfx(path);
+ break;
case BCONTEXT_DATA:
found = buttons_context_path_data(path, -1);
break;
@@ -553,7 +572,14 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
found = buttons_context_path_particle(path);
break;
case BCONTEXT_MATERIAL:
- found = buttons_context_path_material(path);
+ /* NOTE: Grease Pencil materials use different panels... */
+ if (ob && ob->type == OB_GPENCIL) {
+ /* XXX: Why path_data? */
+ found = buttons_context_path_data(path, -1);
+ }
+ else {
+ found = buttons_context_path_material(path);
+ }
break;
case BCONTEXT_TEXTURE:
found = buttons_context_path_texture(C, path, sbuts->texuser);
@@ -626,10 +652,18 @@ void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
if (a == BCONTEXT_DATA) {
ptr = &path->ptr[path->len - 1];
- if (ptr->type)
+ if (ptr->type) {
sbuts->dataicon = RNA_struct_ui_icon(ptr->type);
- else
- sbuts->dataicon = ICON_EMPTY_DATA;
+ }
+ else {
+ Object *ob = CTX_data_active_object(C);
+ if (ob->type == OB_GPENCIL) {
+ sbuts->dataicon = ICON_GREASEPENCIL;
+ }
+ else {
+ sbuts->dataicon = ICON_EMPTY_DATA;
+ }
+ }
}
}
}
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 66684de18ac..de422565abd 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -55,6 +55,7 @@
#include "BKE_layer.h"
#include "BKE_linestyle.h"
#include "BKE_modifier.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
@@ -152,6 +153,19 @@ static void buttons_texture_modifier_foreach(void *userData, Object *ob, Modifie
N_("Modifiers"), RNA_struct_ui_icon(ptr.type), md->name);
}
+static void buttons_texture_modifier_gpencil_foreach(void *userData, Object *ob, GpencilModifierData *md, const char *propname)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ ListBase *users = userData;
+
+ RNA_pointer_create(&ob->id, &RNA_GpencilModifier, md, &ptr);
+ prop = RNA_struct_find_property(&ptr, propname);
+
+ buttons_texture_user_property_add(users, &ob->id, ptr, prop,
+ N_("Grease Pencil Modifiers"), RNA_struct_ui_icon(ptr.type), md->name);
+}
+
static void buttons_texture_users_from_context(ListBase *users, const bContext *C, SpaceButs *sbuts)
{
Scene *scene = NULL;
@@ -203,6 +217,9 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext *
/* modifiers */
modifiers_foreachTexLink(ob, buttons_texture_modifier_foreach, users);
+ /* grease pencil modifiers */
+ BKE_gpencil_modifiers_foreachTexLink(ob, buttons_texture_modifier_gpencil_foreach, users);
+
/* particle systems */
if (psys && !limited_mode) {
for (a = 0; a < MAX_MTEX; a++) {
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 6f7a4ca971a..62115aea11d 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -180,6 +180,9 @@ static void buttons_main_region_layout_properties(const bContext *C, SpaceButs *
case BCONTEXT_MODIFIER:
contexts[0] = "modifier";
break;
+ case BCONTEXT_SHADERFX:
+ contexts[0] = "shaderfx";
+ break;
case BCONTEXT_CONSTRAINT:
contexts[0] = "constraint";
break;
@@ -200,8 +203,9 @@ static void buttons_main_region_layout_tool(const bContext *C, ARegion *ar)
const char *contexts[3] = {NULL};
const WorkSpace *workspace = CTX_wm_workspace(C);
+ const int mode = CTX_data_mode_enum(C);
+
if (workspace->tools_space_type == SPACE_VIEW3D) {
- const int mode = CTX_data_mode_enum(C);
switch (mode) {
case CTX_MODE_EDIT_MESH:
ARRAY_SET_ITEMS(contexts, ".mesh_edit");
@@ -245,12 +249,39 @@ static void buttons_main_region_layout_tool(const bContext *C, ARegion *ar)
case CTX_MODE_OBJECT:
ARRAY_SET_ITEMS(contexts, ".objectmode");
break;
+ case CTX_MODE_GPENCIL_PAINT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_paint");
+ break;
+ case CTX_MODE_GPENCIL_SCULPT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt");
+ break;
+ case CTX_MODE_GPENCIL_WEIGHT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_weight");
+ break;
}
}
else if (workspace->tools_space_type == SPACE_IMAGE) {
/* TODO */
}
+ /* for grease pencil we don't use tool system yet, so we need check outside
+ * workspace->tools_space_type because this value is not available
+ */
+ switch (mode) {
+ case CTX_MODE_GPENCIL_PAINT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_paint");
+ break;
+ case CTX_MODE_GPENCIL_SCULPT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt");
+ break;
+ case CTX_MODE_GPENCIL_WEIGHT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_weight");
+ break;
+ case CTX_MODE_GPENCIL_EDIT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_edit");
+ break;
+ }
+
const bool vertical = true;
ED_region_panels_layout_ex(C, ar, contexts, -1, vertical);
}
@@ -495,6 +526,14 @@ static void buttons_area_listener(
break;
}
break;
+ case NC_GPENCIL:
+ switch(wmn->data) {
+ case ND_DATA:
+ if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
+ ED_area_tag_redraw(sa);
+ break;
+ }
+ break;
case NC_NODE:
if (wmn->action == NA_SELECTED) {
ED_area_tag_redraw(sa);
diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c
index db5f6c2451c..6953b7cfb71 100644
--- a/source/blender/editors/space_clip/clip_buttons.c
+++ b/source/blender/editors/space_clip/clip_buttons.c
@@ -107,7 +107,7 @@ void uiTemplateMovieClip(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
uiLayoutSetContextPointer(layout, "edit_movieclip", &clipptr);
if (!compact)
- uiTemplateID(layout, C, ptr, propname, NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, propname, NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (clip) {
uiLayout *col;
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 2b98ff43c5f..725c2b7fa6d 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -236,7 +236,7 @@ static SpaceLink *clip_new(const ScrArea *sa, const Scene *scene)
sc = MEM_callocN(sizeof(SpaceClip), "initclip");
sc->spacetype = SPACE_CLIP;
sc->flag = SC_SHOW_MARKER_PATTERN | SC_SHOW_TRACK_PATH |
- SC_SHOW_GRAPH_TRACKS_MOTION | SC_SHOW_GRAPH_FRAMES | SC_SHOW_GPENCIL;
+ SC_SHOW_GRAPH_TRACKS_MOTION | SC_SHOW_GRAPH_FRAMES | SC_SHOW_ANNOTATION;
sc->zoom = 1.0f;
sc->path_length = 20;
sc->scopes.track_preview_height = 120;
@@ -1196,7 +1196,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *ar)
clip_draw_cache_and_notes(C, sc, ar);
- if (sc->flag & SC_SHOW_GPENCIL) {
+ if (sc->flag & SC_SHOW_ANNOTATION) {
/* Grease Pencil */
clip_draw_grease_pencil((bContext *)C, true);
}
@@ -1204,7 +1204,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *ar)
/* reset view matrix */
UI_view2d_view_restore(C);
- if (sc->flag & SC_SHOW_GPENCIL) {
+ if (sc->flag & SC_SHOW_ANNOTATION) {
/* draw Grease Pencil - screen space only */
clip_draw_grease_pencil((bContext *)C, false);
}
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 1d8c6721b64..afcae7a27ab 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -876,7 +876,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
if (!compact) {
uiTemplateID(
layout, C, ptr, propname,
- ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
}
if (ima) {
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 8aa37bb5e16..fdf9d6df374 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -32,6 +32,7 @@
#include "DNA_armature_types.h"
#include "DNA_curve_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
@@ -55,6 +56,7 @@
#include "BKE_particle.h"
#include "BKE_editmesh.h"
#include "BKE_object.h"
+#include "BKE_gpencil.h"
#include "ED_info.h"
#include "ED_armature.h"
@@ -72,6 +74,7 @@ typedef struct SceneStats {
int totobj, totobjsel;
int totlamp, totlampsel;
int tottri;
+ int totgplayer, totgpframe, totgpstroke, totgppoint;
char infostr[MAX_INFO_LEN];
} SceneStats;
@@ -85,6 +88,8 @@ typedef struct SceneStatsFmt {
char totobj[MAX_INFO_NUM_LEN], totobjsel[MAX_INFO_NUM_LEN];
char totlamp[MAX_INFO_NUM_LEN], totlampsel[MAX_INFO_NUM_LEN];
char tottri[MAX_INFO_NUM_LEN];
+ char totgplayer[MAX_INFO_NUM_LEN], totgpframe[MAX_INFO_NUM_LEN];
+ char totgpstroke[MAX_INFO_NUM_LEN], totgppoint[MAX_INFO_NUM_LEN];
} SceneStatsFmt;
static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
@@ -144,6 +149,20 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
}
break;
}
+ case OB_GPENCIL:
+ {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ /* GPXX Review if we can move to other place when object change
+ * maybe to depsgraph evaluation
+ */
+ BKE_gpencil_stats_update(gpd);
+
+ stats->totgplayer = gpd->totlayer;
+ stats->totgpframe = gpd->totframe;
+ stats->totgpstroke = gpd->totstroke;
+ stats->totgppoint = gpd->totpoint;
+ break;
+ }
}
}
@@ -442,6 +461,11 @@ static void stats_string(ViewLayer *view_layer)
SCENE_STATS_FMT_INT(tottri);
+ SCENE_STATS_FMT_INT(totgplayer);
+ SCENE_STATS_FMT_INT(totgpframe);
+ SCENE_STATS_FMT_INT(totgpstroke);
+ SCENE_STATS_FMT_INT(totgppoint);
+
#undef SCENE_STATS_FMT_INT
@@ -501,6 +525,14 @@ static void stats_string(ViewLayer *view_layer)
ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%s/%s %s%s"),
stats_fmt.totbonesel, stats_fmt.totbone, memstr, gpumemstr);
}
+ else if ((ob) && (ob->type == OB_GPENCIL)) {
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
+ IFACE_("Layers:%s | Frames:%s | Strokes:%s | Points:%s"),
+ stats_fmt.totgplayer, stats_fmt.totgpframe, stats_fmt.totgpstroke, stats_fmt.totgppoint);
+
+ ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
+ }
else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) {
ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s | Tris:%s%s"), stats_fmt.totvert,
stats_fmt.tottri, gpumemstr);
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 57464cbf092..40caf919848 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -145,6 +145,7 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_PALETTE:
{
/* for these channels, we only do AnimData */
if (ale->adt && adt_ptr) {
@@ -287,7 +288,7 @@ static void nla_panel_animdata(const bContext *C, Panel *pa)
row = uiLayoutRow(layout, true);
uiTemplateID(
row, (bContext *)C, &adt_ptr, "action",
- "ACTION_OT_new", NULL, "NLA_OT_action_unlink", UI_TEMPLATE_ID_FILTER_ALL);
+ "ACTION_OT_new", NULL, "NLA_OT_action_unlink", UI_TEMPLATE_ID_FILTER_ALL, false);
/* extrapolation */
row = uiLayoutRow(layout, true);
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 3368ad4fe8d..51177a77f0d 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -182,6 +182,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_PALETTE:
{
/* sanity checking... */
if (ale->adt) {
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index d1ad8cb396c..f284fa015b8 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -744,7 +744,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
- uiTemplateID(layout, C, ptr, "image", "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "image", "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
@@ -775,7 +775,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
uiTemplateID(
layout, C, ptr, "image",
- "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
@@ -793,7 +793,7 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
uiTemplateID(
layout, C, ptr, "image",
- "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!ima)
return;
@@ -1274,7 +1274,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
uiTemplateID(
layout, C, ptr, "image",
- "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!node->id) return;
imaptr = RNA_pointer_get(ptr, "image");
@@ -1304,7 +1304,7 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer
const char *layer_name;
char scene_name[MAX_ID_NAME - 2];
- uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!node->id) return;
@@ -1418,7 +1418,7 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "use_preview", 0, NULL, ICON_NONE);
- uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "use_zbuffer", 0, NULL, ICON_NONE);
@@ -1985,7 +1985,7 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe
static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
}
static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1993,7 +1993,7 @@ static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, Point
bNode *node = ptr->data;
PointerRNA clipptr;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!node->id)
return;
@@ -2007,7 +2007,7 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!node->id)
return;
@@ -2031,7 +2031,7 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!node->id)
return;
@@ -2339,7 +2339,7 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
uiItemR(layout, ptr, "use_antialiasing", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "use_feather", 0, NULL, ICON_NONE);
@@ -2361,7 +2361,7 @@ static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, Point
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (node->id) {
MovieClip *clip = (MovieClip *) node->id;
@@ -2397,7 +2397,7 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (node->id) {
MovieClip *clip = (MovieClip *) node->id;
@@ -2437,7 +2437,7 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P
bNode *node = ptr->data;
NodePlaneTrackDeformData *data = node->storage;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (node->id) {
MovieClip *clip = (MovieClip *) node->id;
@@ -2838,7 +2838,7 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), Pointe
static void node_texture_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiTemplateID(layout, C, ptr, "image", "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "image", "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
}
static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 435e0018ac0..feab82a59c8 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -32,6 +32,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_lightprobe_types.h"
@@ -50,6 +51,7 @@
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_fcurve.h"
+#include "BKE_gpencil.h"
#include "BKE_global.h"
#include "BKE_idcode.h"
#include "BKE_layer.h"
@@ -438,12 +440,16 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
}
case TSE_GP_LAYER:
{
- bGPdata *gpd = (bGPdata *)tselem->id; // id = GP Datablock
+ bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */
bGPDlayer *gpl = te->directdata;
+ /* always make layer active */
+ BKE_gpencil_layer_setactive(gpd, gpl);
+
// XXX: name needs translation stuff
BLI_uniquename(&gpd->layers, gpl, "GP Layer", '.',
offsetof(bGPDlayer, info), sizeof(gpl->info));
+
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, gpd);
break;
}
@@ -872,39 +878,6 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
}
-static void UNUSED_FUNCTION(tselem_draw_gp_icon_uibut)(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl)
-{
- /* restrict column clip - skip it for now... */
- if (arg->x >= arg->xmax) {
- /* pass */
- }
- else {
- PointerRNA ptr;
- const float eps = 0.001f;
- const bool is_stroke_visible = (gpl->color[3] > eps);
- const bool is_fill_visible = (gpl->fill[3] > eps);
- float w = 0.5f * UI_UNIT_X;
- float h = 0.85f * UI_UNIT_Y;
-
- RNA_pointer_create(id, &RNA_GPencilLayer, gpl, &ptr);
-
- UI_block_align_begin(arg->block);
-
- UI_block_emboss_set(arg->block, is_stroke_visible ? UI_EMBOSS : UI_EMBOSS_NONE);
- uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb, arg->yb, w, h,
- &ptr, "color", -1,
- 0, 0, 0, 0, NULL);
-
- UI_block_emboss_set(arg->block, is_fill_visible ? UI_EMBOSS : UI_EMBOSS_NONE);
- uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb + w, arg->yb, w, h,
- &ptr, "fill_color", -1,
- 0, 0, 0, 0, NULL);
-
- UI_block_emboss_set(arg->block, UI_EMBOSS_NONE);
- UI_block_align_end(arg->block);
- }
-}
-
static void tselem_draw_icon(
uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te,
float alpha, const bool is_clickable)
@@ -969,156 +942,212 @@ static void tselem_draw_icon(
case TSE_MODIFIER:
{
Object *ob = (Object *)tselem->id;
- ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr);
- switch ((ModifierType)md->type) {
- case eModifierType_Subsurf:
- ICON_DRAW(ICON_MOD_SUBSURF);
- break;
- case eModifierType_Armature:
- ICON_DRAW(ICON_MOD_ARMATURE);
- break;
- case eModifierType_Lattice:
- ICON_DRAW(ICON_MOD_LATTICE);
- break;
- case eModifierType_Curve:
- ICON_DRAW(ICON_MOD_CURVE);
- break;
- case eModifierType_Build:
- ICON_DRAW(ICON_MOD_BUILD);
- break;
- case eModifierType_Mirror:
- ICON_DRAW(ICON_MOD_MIRROR);
- break;
- case eModifierType_Decimate:
- ICON_DRAW(ICON_MOD_DECIM);
- break;
- case eModifierType_Wave:
- ICON_DRAW(ICON_MOD_WAVE);
- break;
- case eModifierType_Hook:
- ICON_DRAW(ICON_HOOK);
- break;
- case eModifierType_Softbody:
- ICON_DRAW(ICON_MOD_SOFT);
- break;
- case eModifierType_Boolean:
- ICON_DRAW(ICON_MOD_BOOLEAN);
- break;
- case eModifierType_ParticleSystem:
- ICON_DRAW(ICON_MOD_PARTICLES);
- break;
- case eModifierType_ParticleInstance:
- ICON_DRAW(ICON_MOD_PARTICLES);
- break;
- case eModifierType_EdgeSplit:
- ICON_DRAW(ICON_MOD_EDGESPLIT);
- break;
- case eModifierType_Array:
- ICON_DRAW(ICON_MOD_ARRAY);
- break;
- case eModifierType_UVProject:
- case eModifierType_UVWarp: /* TODO, get own icon */
- ICON_DRAW(ICON_MOD_UVPROJECT);
- break;
- case eModifierType_Displace:
- ICON_DRAW(ICON_MOD_DISPLACE);
- break;
- case eModifierType_Shrinkwrap:
- ICON_DRAW(ICON_MOD_SHRINKWRAP);
- break;
- case eModifierType_Cast:
- ICON_DRAW(ICON_MOD_CAST);
- break;
- case eModifierType_MeshDeform:
- case eModifierType_SurfaceDeform:
- ICON_DRAW(ICON_MOD_MESHDEFORM);
- break;
- case eModifierType_Bevel:
- ICON_DRAW(ICON_MOD_BEVEL);
- break;
- case eModifierType_Smooth:
- case eModifierType_LaplacianSmooth:
- case eModifierType_CorrectiveSmooth:
- ICON_DRAW(ICON_MOD_SMOOTH);
- break;
- case eModifierType_SimpleDeform:
- ICON_DRAW(ICON_MOD_SIMPLEDEFORM);
- break;
- case eModifierType_Mask:
- ICON_DRAW(ICON_MOD_MASK);
- break;
- case eModifierType_Cloth:
- ICON_DRAW(ICON_MOD_CLOTH);
- break;
- case eModifierType_Explode:
- ICON_DRAW(ICON_MOD_EXPLODE);
- break;
- case eModifierType_Collision:
- case eModifierType_Surface:
- ICON_DRAW(ICON_MOD_PHYSICS);
- break;
- case eModifierType_Fluidsim:
- ICON_DRAW(ICON_MOD_FLUIDSIM);
- break;
- case eModifierType_Multires:
- ICON_DRAW(ICON_MOD_MULTIRES);
- break;
- case eModifierType_Smoke:
- ICON_DRAW(ICON_MOD_SMOKE);
- break;
- case eModifierType_Solidify:
- ICON_DRAW(ICON_MOD_SOLIDIFY);
- break;
- case eModifierType_Screw:
- ICON_DRAW(ICON_MOD_SCREW);
- break;
- case eModifierType_Remesh:
- ICON_DRAW(ICON_MOD_REMESH);
- break;
- case eModifierType_WeightVGEdit:
- case eModifierType_WeightVGMix:
- case eModifierType_WeightVGProximity:
- ICON_DRAW(ICON_MOD_VERTEX_WEIGHT);
- break;
- case eModifierType_DynamicPaint:
- ICON_DRAW(ICON_MOD_DYNAMICPAINT);
- break;
- case eModifierType_Ocean:
- ICON_DRAW(ICON_MOD_OCEAN);
- break;
- case eModifierType_Warp:
- ICON_DRAW(ICON_MOD_WARP);
- break;
- case eModifierType_Skin:
- ICON_DRAW(ICON_MOD_SKIN);
- break;
- case eModifierType_Triangulate:
- ICON_DRAW(ICON_MOD_TRIANGULATE);
- break;
- case eModifierType_MeshCache:
- ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
- break;
- case eModifierType_MeshSequenceCache:
- ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
- break;
- case eModifierType_Wireframe:
- ICON_DRAW(ICON_MOD_WIREFRAME);
- break;
- case eModifierType_LaplacianDeform:
- ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
- break;
- case eModifierType_DataTransfer:
- ICON_DRAW(ICON_MOD_DATA_TRANSFER);
- break;
- case eModifierType_NormalEdit:
- ICON_DRAW(ICON_MOD_NORMALEDIT);
- break;
- /* Default */
- case eModifierType_None:
- case eModifierType_ShapeKey:
- case NUM_MODIFIER_TYPES:
- ICON_DRAW(ICON_DOT);
- break;
+ if (ob->type != OB_GPENCIL) {
+ ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr);
+ switch ((ModifierType)md->type) {
+ case eModifierType_Subsurf:
+ ICON_DRAW(ICON_MOD_SUBSURF);
+ break;
+ case eModifierType_Armature:
+ ICON_DRAW(ICON_MOD_ARMATURE);
+ break;
+ case eModifierType_Lattice:
+ ICON_DRAW(ICON_MOD_LATTICE);
+ break;
+ case eModifierType_Curve:
+ ICON_DRAW(ICON_MOD_CURVE);
+ break;
+ case eModifierType_Build:
+ ICON_DRAW(ICON_MOD_BUILD);
+ break;
+ case eModifierType_Mirror:
+ ICON_DRAW(ICON_MOD_MIRROR);
+ break;
+ case eModifierType_Decimate:
+ ICON_DRAW(ICON_MOD_DECIM);
+ break;
+ case eModifierType_Wave:
+ ICON_DRAW(ICON_MOD_WAVE);
+ break;
+ case eModifierType_Hook:
+ ICON_DRAW(ICON_HOOK);
+ break;
+ case eModifierType_Softbody:
+ ICON_DRAW(ICON_MOD_SOFT);
+ break;
+ case eModifierType_Boolean:
+ ICON_DRAW(ICON_MOD_BOOLEAN);
+ break;
+ case eModifierType_ParticleSystem:
+ ICON_DRAW(ICON_MOD_PARTICLES);
+ break;
+ case eModifierType_ParticleInstance:
+ ICON_DRAW(ICON_MOD_PARTICLES);
+ break;
+ case eModifierType_EdgeSplit:
+ ICON_DRAW(ICON_MOD_EDGESPLIT);
+ break;
+ case eModifierType_Array:
+ ICON_DRAW(ICON_MOD_ARRAY);
+ break;
+ case eModifierType_UVProject:
+ case eModifierType_UVWarp: /* TODO, get own icon */
+ ICON_DRAW(ICON_MOD_UVPROJECT);
+ break;
+ case eModifierType_Displace:
+ ICON_DRAW(ICON_MOD_DISPLACE);
+ break;
+ case eModifierType_Shrinkwrap:
+ ICON_DRAW(ICON_MOD_SHRINKWRAP);
+ break;
+ case eModifierType_Cast:
+ ICON_DRAW(ICON_MOD_CAST);
+ break;
+ case eModifierType_MeshDeform:
+ case eModifierType_SurfaceDeform:
+ ICON_DRAW(ICON_MOD_MESHDEFORM);
+ break;
+ case eModifierType_Bevel:
+ ICON_DRAW(ICON_MOD_BEVEL);
+ break;
+ case eModifierType_Smooth:
+ case eModifierType_LaplacianSmooth:
+ case eModifierType_CorrectiveSmooth:
+ ICON_DRAW(ICON_MOD_SMOOTH);
+ break;
+ case eModifierType_SimpleDeform:
+ ICON_DRAW(ICON_MOD_SIMPLEDEFORM);
+ break;
+ case eModifierType_Mask:
+ ICON_DRAW(ICON_MOD_MASK);
+ break;
+ case eModifierType_Cloth:
+ ICON_DRAW(ICON_MOD_CLOTH);
+ break;
+ case eModifierType_Explode:
+ ICON_DRAW(ICON_MOD_EXPLODE);
+ break;
+ case eModifierType_Collision:
+ case eModifierType_Surface:
+ ICON_DRAW(ICON_MOD_PHYSICS);
+ break;
+ case eModifierType_Fluidsim:
+ ICON_DRAW(ICON_MOD_FLUIDSIM);
+ break;
+ case eModifierType_Multires:
+ ICON_DRAW(ICON_MOD_MULTIRES);
+ break;
+ case eModifierType_Smoke:
+ ICON_DRAW(ICON_MOD_SMOKE);
+ break;
+ case eModifierType_Solidify:
+ ICON_DRAW(ICON_MOD_SOLIDIFY);
+ break;
+ case eModifierType_Screw:
+ ICON_DRAW(ICON_MOD_SCREW);
+ break;
+ case eModifierType_Remesh:
+ ICON_DRAW(ICON_MOD_REMESH);
+ break;
+ case eModifierType_WeightVGEdit:
+ case eModifierType_WeightVGMix:
+ case eModifierType_WeightVGProximity:
+ ICON_DRAW(ICON_MOD_VERTEX_WEIGHT);
+ break;
+ case eModifierType_DynamicPaint:
+ ICON_DRAW(ICON_MOD_DYNAMICPAINT);
+ break;
+ case eModifierType_Ocean:
+ ICON_DRAW(ICON_MOD_OCEAN);
+ break;
+ case eModifierType_Warp:
+ ICON_DRAW(ICON_MOD_WARP);
+ break;
+ case eModifierType_Skin:
+ ICON_DRAW(ICON_MOD_SKIN);
+ break;
+ case eModifierType_Triangulate:
+ ICON_DRAW(ICON_MOD_TRIANGULATE);
+ break;
+ case eModifierType_MeshCache:
+ ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
+ break;
+ case eModifierType_MeshSequenceCache:
+ ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
+ break;
+ case eModifierType_Wireframe:
+ ICON_DRAW(ICON_MOD_WIREFRAME);
+ break;
+ case eModifierType_LaplacianDeform:
+ ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
+ break;
+ case eModifierType_DataTransfer:
+ ICON_DRAW(ICON_MOD_DATA_TRANSFER);
+ break;
+ case eModifierType_NormalEdit:
+ ICON_DRAW(ICON_MOD_NORMALEDIT);
+ break;
+ /* Default */
+ case eModifierType_None:
+ case eModifierType_ShapeKey:
+
+ case NUM_MODIFIER_TYPES:
+ ICON_DRAW(ICON_DOT);
+ break;
+ }
+ }
+ else {
+ /* grease pencil modifiers */
+ GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, tselem->nr);
+ switch ((GpencilModifierType)md->type) {
+ case eGpencilModifierType_Noise:
+ ICON_DRAW(ICON_RNDCURVE);
+ break;
+ case eGpencilModifierType_Subdiv:
+ ICON_DRAW(ICON_MOD_SUBSURF);
+ break;
+ case eGpencilModifierType_Thick:
+ ICON_DRAW(ICON_MAN_ROT);
+ break;
+ case eGpencilModifierType_Tint:
+ ICON_DRAW(ICON_COLOR);
+ break;
+ case eGpencilModifierType_Instance:
+ ICON_DRAW(ICON_MOD_ARRAY);
+ break;
+ case eGpencilModifierType_Build:
+ ICON_DRAW(ICON_MOD_BUILD);
+ break;
+ case eGpencilModifierType_Opacity:
+ ICON_DRAW(ICON_MOD_MASK);
+ break;
+ case eGpencilModifierType_Color:
+ ICON_DRAW(ICON_GROUP_VCOL);
+ break;
+ case eGpencilModifierType_Lattice:
+ ICON_DRAW(ICON_MOD_LATTICE);
+ break;
+ case eGpencilModifierType_Mirror:
+ ICON_DRAW(ICON_MOD_MIRROR);
+ break;
+ case eGpencilModifierType_Simplify:
+ ICON_DRAW(ICON_MOD_DECIM);
+ break;
+ case eGpencilModifierType_Smooth:
+ ICON_DRAW(ICON_MOD_SMOOTH);
+ break;
+ case eGpencilModifierType_Hook:
+ ICON_DRAW(ICON_HOOK);
+ break;
+ case eGpencilModifierType_Offset:
+ ICON_DRAW(ICON_MOD_DISPLACE);
+ break;
+
+ /* Default */
+ default:
+ ICON_DRAW(ICON_DOT);
+ break;
+ }
}
break;
}
@@ -1185,11 +1214,18 @@ static void tselem_draw_icon(
ICON_DRAW(ICON_GROUP);
break;
/* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */
-#if 0
case TSE_GP_LAYER:
- tselem_draw_gp_icon_uibut(&arg, tselem->id, te->directdata);
+ {
+ /* indicate whether layer is active */
+ bGPDlayer *gpl = te->directdata;
+ if (gpl->flag & GP_LAYER_ACTIVE) {
+ ICON_DRAW(ICON_GREASEPENCIL);
+ }
+ else {
+ ICON_DRAW(ICON_DOT);
+ }
break;
-#endif
+ }
default:
ICON_DRAW(ICON_DOT);
break;
@@ -1229,6 +1265,9 @@ static void tselem_draw_icon(
ICON_CLICK_DRAW(ICON_OUTLINER_OB_EMPTY);
}
break;
+ case OB_GPENCIL:
+ ICON_CLICK_DRAW(ICON_OUTLINER_OB_GREASEPENCIL); break;
+ break;
}
}
else {
@@ -1304,7 +1343,7 @@ static void tselem_draw_icon(
case ID_LS:
tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break;
case ID_GD:
- tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break;
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_GREASEPENCIL); break;
case ID_LP:
{
LightProbe * lp = (LightProbe *)tselem->id;
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 7ab13f36953..ec5e11520a6 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -39,6 +39,7 @@
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_world_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
@@ -46,9 +47,11 @@
#include "BKE_armature.h"
#include "BKE_collection.h"
#include "BKE_context.h"
+#include "BKE_gpencil.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_workspace.h"
@@ -60,6 +63,7 @@
#include "ED_screen.h"
#include "ED_sequencer.h"
#include "ED_undo.h"
+#include "ED_gpencil.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -470,6 +474,28 @@ static eOLDrawState tree_element_active_defgroup(
return OL_DRAWSEL_NONE;
}
+static eOLDrawState UNUSED_FUNCTION(tree_element_active_gplayer)(
+ bContext *C, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
+{
+ bGPdata *gpd = (bGPdata *)tselem->id;
+ bGPDlayer *gpl = te->directdata;
+
+ /* We can only have a single "active" layer at a time
+ * and there must always be an active layer...
+ */
+ if (set != OL_SETSEL_NONE) {
+ if (gpl) {
+ BKE_gpencil_layer_setactive(gpd, gpl);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, gpd);
+ }
+ }
+ else {
+ return OL_DRAWSEL_NORMAL;
+ }
+
+ return OL_DRAWSEL_NONE;
+}
+
static eOLDrawState tree_element_active_posegroup(
bContext *C, Scene *UNUSED(scene), ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
{
@@ -1006,6 +1032,10 @@ static void do_outliner_item_activate_tree_element(
}
}
}
+ else if (ELEM(te->idcode, ID_GD)) {
+ /* set grease pencil to object mode */
+ WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
+ }
else { // rest of types
tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, false);
}
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 28890e42139..539df3aa085 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -319,8 +319,6 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s
if (outliner_animdata_test(sce->adt))
outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0);
- /* Grease Pencil */
- outliner_add_element(soops, lb, sce->gpd, te, 0, 0);
}
TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index e45159124e8..6113922c02e 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -168,6 +168,10 @@ static void topbar_main_region_listener(wmWindow *UNUSED(win), ScrArea *UNUSED(s
if (wmn->data == ND_SPACE_VIEW3D)
ED_region_tag_redraw(ar);
break;
+ case NC_GPENCIL:
+ if (wmn->data == ND_DATA)
+ ED_region_tag_redraw(ar);
+ break;
}
}
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index c0abbe636c3..3649c6f6dbb 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -80,6 +80,7 @@
#include "BKE_subsurf.h"
#include "BKE_unit.h"
#include "BKE_tracking.h"
+#include "BKE_gpencil.h"
#include "BKE_editmesh.h"
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 2577077002e..c1776ef18e7 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -36,6 +36,7 @@
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_gpencil_types.h"
#include "MEM_guardedalloc.h"
@@ -335,12 +336,18 @@ static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene)
v3d->gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR;
v3d->flag = V3D_SELECT_OUTLINE;
- v3d->flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_GPENCIL;
+ v3d->flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_ANNOTATION;
v3d->lens = 50.0f;
v3d->near = 0.01f;
v3d->far = 1000.0f;
+ v3d->overlay.gpencil_grid_scale = 1.0; // Scales
+ v3d->overlay.gpencil_grid_lines = GP_DEFAULT_GRID_LINES; // NUmber of Lines
+ v3d->overlay.gpencil_paper_opacity = 0.5f;
+ v3d->overlay.gpencil_grid_axis = V3D_GP_GRID_AXIS_Y;
+ v3d->overlay.gpencil_grid_opacity = 0.9f;
+
v3d->bundle_size = 0.2f;
v3d->bundle_drawtype = OB_PLAINAXES;
@@ -350,6 +357,10 @@ static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene)
v3d->stereo3d_convergence_alpha = 0.15f;
v3d->stereo3d_volume_alpha = 0.05f;
+ /* grease pencil settings */
+ v3d->vertex_opacity = 1.0f;
+ v3d->flag3 |= V3D_GP_SHOW_EDIT_LINES;
+
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for view3d");
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 941f9262694..0157bc567ca 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1593,7 +1593,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
v3d.flag2 = V3D_RENDER_OVERRIDE;
if (draw_flags & V3D_OFSDRAW_USE_GPENCIL) {
- v3d.flag2 |= V3D_SHOW_GPENCIL;
+ v3d.flag2 |= V3D_SHOW_ANNOTATION;
}
if (draw_flags & V3D_OFSDRAW_USE_SOLID_TEX) {
v3d.flag2 |= V3D_SOLID_TEX;
diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c
index 94cd4dfc73d..45e4c4b4676 100644
--- a/source/blender/editors/space_view3d/view3d_draw_legacy.c
+++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c
@@ -881,7 +881,7 @@ void ED_view3d_draw_depth_gpencil(
GPU_depth_test(true);
- if (v3d->flag2 & V3D_SHOW_GPENCIL) {
+ if (v3d->flag2 & V3D_SHOW_ANNOTATION) {
ED_gpencil_draw_view3d(NULL, scene, view_layer, depsgraph, v3d, ar, true);
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index e94d3a13225..468b33ea9a6 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -52,6 +52,7 @@
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_font.h"
+#include "BKE_gpencil.h"
#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -77,7 +78,6 @@
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_mesh.h"
-#include "ED_gpencil.h"
#include "ED_view3d.h"
#include "ED_transform_snap_object_context.h"
@@ -2811,7 +2811,7 @@ static int viewselected_exec(bContext *C, wmOperator *op)
Depsgraph *depsgraph = CTX_data_depsgraph(C);
ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
bGPdata *gpd = CTX_data_gpencil_data(C);
- const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
+ const bool is_gp_edit = GPENCIL_ANY_MODE(gpd);
const bool is_face_map = ((is_gp_edit == false) && ar->gizmo_map &&
WM_gizmomap_is_any_selected(ar->gizmo_map));
Object *ob_eval = OBACT(view_layer_eval);
@@ -2850,9 +2850,7 @@ static int viewselected_exec(bContext *C, wmOperator *op)
{
/* we're only interested in selected points here... */
if ((gps->flag & GP_STROKE_SELECT) && (gps->flag & GP_STROKE_3DSPACE)) {
- if (ED_gpencil_stroke_minmax(gps, true, min, max)) {
- ok = true;
- }
+ ok |= BKE_gpencil_stroke_minmax(gps, true, min, max);
}
}
CTX_DATA_END;
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index c716692eb9b..d5ef7cdf441 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -36,13 +36,17 @@
#include "BKE_object.h"
#include "BKE_unit.h"
+#include "BKE_material.h"
+#include "BKE_main.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_view3d_types.h"
#include "BIF_gl.h"
+#include "ED_gpencil.h"
#include "ED_screen.h"
#include "ED_transform_snap_object_context.h"
#include "ED_view3d.h"
@@ -385,37 +389,28 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
// RulerInfo *ruler_info = gzgroup->customdata;
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+
+ bGPdata *gpd;
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
- bGPDpalette *palette;
- bGPDpalettecolor *palcolor;
RulerItem *ruler_item;
const char *ruler_name = RULER_ID;
bool changed = false;
if (scene->gpd == NULL) {
- scene->gpd = BKE_gpencil_data_addnew(bmain, "GPencil");
+ scene->gpd = BKE_gpencil_data_addnew(bmain, "Annotations");
}
+ gpd = scene->gpd;
- gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
+ gpl = BLI_findstring(&gpd->layers, ruler_name, offsetof(bGPDlayer, info));
if (gpl == NULL) {
- gpl = BKE_gpencil_layer_addnew(scene->gpd, ruler_name, false);
+ gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false);
+ copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
gpl->thickness = 1;
gpl->flag |= GP_LAYER_HIDE;
}
- /* try to get active palette or create a new one */
- palette = BKE_gpencil_palette_getactive(scene->gpd);
- if (palette == NULL) {
- palette = BKE_gpencil_palette_addnew(scene->gpd, DATA_("GP_Palette"), true);
- }
- /* try to get color with the ruler name or create a new one */
- palcolor = BKE_gpencil_palettecolor_getbyname(palette, (char *)ruler_name);
- if (palcolor == NULL) {
- palcolor = BKE_gpencil_palettecolor_addnew(palette, (char *)ruler_name, true);
- }
-
gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
BKE_gpencil_free_strokes(gpf);
@@ -428,6 +423,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
if (ruler_item->flag & RULERITEM_USE_ANGLE) {
gps->totpoints = 3;
pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights");
for (j = 0; j < 3; j++) {
copy_v3_v3(&pt->x, ruler_item->co[j]);
pt->pressure = 1.0f;
@@ -438,6 +434,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
else {
gps->totpoints = 2;
pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights");
for (j = 0; j < 3; j += 2) {
copy_v3_v3(&pt->x, ruler_item->co[j]);
pt->pressure = 1.0f;
@@ -447,9 +444,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
}
gps->flag = GP_STROKE_3DSPACE;
gps->thickness = 3;
- /* assign color to stroke */
- BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname));
- gps->palcolor = palcolor;
+
BLI_addtail(&gpf->strokes, gps);
changed = true;
}
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index 690fc5e3bdb..0475159712b 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -26,9 +26,11 @@
/* defines VIEW3D_OT_ruler modal operator */
+#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_brush_types.h"
#include "MEM_guardedalloc.h"
@@ -40,6 +42,7 @@
#include "BKE_context.h"
#include "BKE_gpencil.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_unit.h"
#include "BIF_gl.h"
@@ -51,6 +54,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_gpencil.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_transform_snap_object_context.h"
@@ -300,37 +304,28 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
- bGPDpalette *palette;
- bGPDpalettecolor *palcolor;
RulerItem *ruler_item;
const char *ruler_name = RULER_ID;
bool changed = false;
+ /* FIXME: This needs to be reviewed. Should it keep being done like this? */
if (scene->gpd == NULL) {
- scene->gpd = BKE_gpencil_data_addnew(bmain, "GPencil");
+ scene->gpd = BKE_gpencil_data_addnew(bmain, "Annotations");
}
+ bGPdata *gpd = scene->gpd;
- gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
+ gpl = BLI_findstring(&gpd->layers, ruler_name, offsetof(bGPDlayer, info));
if (gpl == NULL) {
- gpl = BKE_gpencil_layer_addnew(scene->gpd, ruler_name, false);
+ gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false);
+ copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
gpl->thickness = 1;
gpl->flag |= GP_LAYER_HIDE;
}
- /* try to get active palette or create a new one */
- palette = BKE_gpencil_palette_getactive(scene->gpd);
- if (palette == NULL) {
- palette = BKE_gpencil_palette_addnew(scene->gpd, DATA_("GP_Palette"), true);
- }
- /* try to get color with the ruler name or create a new one */
- palcolor = BKE_gpencil_palettecolor_getbyname(palette, (char *)ruler_name);
- if (palcolor == NULL) {
- palcolor = BKE_gpencil_palettecolor_addnew(palette, (char *)ruler_name, true);
- }
-
gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
BKE_gpencil_free_strokes(gpf);
@@ -343,6 +338,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
if (ruler_item->flag & RULERITEM_USE_ANGLE) {
gps->totpoints = 3;
pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights");
for (j = 0; j < 3; j++) {
copy_v3_v3(&pt->x, ruler_item->co[j]);
pt->pressure = 1.0f;
@@ -353,6 +349,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
else {
gps->totpoints = 2;
pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights");
for (j = 0; j < 3; j += 2) {
copy_v3_v3(&pt->x, ruler_item->co[j]);
pt->pressure = 1.0f;
@@ -362,9 +359,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
}
gps->flag = GP_STROKE_3DSPACE;
gps->thickness = 3;
- /* assign color to stroke */
- BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname));
- gps->palcolor = palcolor;
+
BLI_addtail(&gpf->strokes, gps);
changed = true;
}
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 7da69c5b2d5..afff5eb7f66 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -44,6 +44,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_tracking_types.h"
+#include "DNA_gpencil_types.h"
#include "MEM_guardedalloc.h"
@@ -76,6 +77,7 @@
#include "BKE_editmesh.h"
#include "BKE_scene.h"
#include "BKE_tracking.h"
+#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
@@ -95,6 +97,7 @@
#include "ED_screen.h"
#include "ED_sculpt.h"
#include "ED_mball.h"
+#include "ED_gpencil.h"
#include "UI_interface.h"
@@ -1675,6 +1678,27 @@ static bool ed_object_select_pick(
if ((oldbasact != basact) && (is_obedit == false)) {
ED_object_base_activate(C, basact); /* adds notifier */
}
+
+ /* Set special modes for grease pencil
+ The grease pencil modes are not real modes, but a hack to make the interface
+ consistent, so need some tricks to keep UI synchronized */
+ // XXX: This stuff neeeds reviewing (Aligorith)
+#if 0
+ if (((oldbasact) && oldbasact->object->type == OB_GPENCIL) || (basact->object->type == OB_GPENCIL)) {
+ /* set cursor */
+ if (ELEM(basact->object->mode == OB_MODE_GPENCIL_PAINT,
+ OB_MODE_GPENCIL_SCULPT,
+ OB_MODE_GPENCIL_WEIGHT)) {
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ }
+ else {
+ /* TODO: maybe is better use restore */
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ }
+ /* set workspace mode */
+ BKE_workspace_object_mode_set(CTX_wm_workspace(C), scene, basact->object->mode);
+ }
+#endif
}
DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 07ef6b9a819..9ad80f2ab12 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -44,6 +44,7 @@
#include "DNA_movieclip_types.h"
#include "DNA_scene_types.h" /* PET modes */
#include "DNA_workspace_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_alloca.h"
#include "BLI_utildefines.h"
@@ -85,6 +86,7 @@
#include "ED_mesh.h"
#include "ED_clip.h"
#include "ED_node.h"
+#include "ED_gpencil.h"
#include "WM_types.h"
#include "WM_api.h"
@@ -101,6 +103,8 @@
#include "transform.h"
+#include "DEG_depsgraph.h"
+
/* Disabling, since when you type you know what you are doing, and being able to set it to zero is handy. */
// #define USE_NUM_NO_ZERO
@@ -571,6 +575,10 @@ void removeAspectRatio(TransInfo *t, float vec[2])
static void viewRedrawForce(const bContext *C, TransInfo *t)
{
if (t->options & CTX_GPENCIL_STROKES) {
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ if (gpd) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+ }
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
}
else if (t->spacetype == SPACE_VIEW3D) {
@@ -1800,7 +1808,23 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
(float)t->mval[1],
};
+
+#if 0 /* XXX: Fix from 1c9690e7607bc990cc4a3e6ba839949bb83a78af cannot be used anymore */
+ if ((t->flag & T_POINTS) && (t->options & CTX_GPENCIL_STROKES)) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob = tc->obedit;
+ float vecrot[3];
+ copy_v3_v3(vecrot, t->center);
+ mul_m4_v3(ob->obmat, vecrot);
+ projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO);
+ }
+ }
+ else {
+ projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
+ }
+#else
projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
+#endif
/* Offset the values for the area region. */
const float offset[2] = {
@@ -3551,7 +3575,25 @@ static void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, f
else
sub_v3_v3(vec, td->center);
- mul_v3_fl(vec, td->factor);
+ /* grease pencil falloff */
+ if (t->options & CTX_GPENCIL_STROKES) {
+ bGPDstroke *gps = (bGPDstroke *)td->extra;
+ mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff);
+
+ /* scale stroke thickness */
+ if (td->val) {
+ snapGridIncrement(t, t->values);
+ applyNumInput(&t->num, t->values);
+
+ float ratio = t->values[0];
+ *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff;
+ CLAMP_MIN(*td->val, 0.001f);
+ }
+
+ }
+ else {
+ mul_v3_fl(vec, td->factor);
+ }
if (t->flag & (T_OBJECT | T_POSE)) {
mul_m3_v3(td->smtx, vec);
@@ -3905,6 +3947,20 @@ static void ElementRotation_ex(TransInfo *t, TransDataContainer *tc, TransData *
mul_m3_m3m3(totmat, mat, td->mtx);
mul_m3_m3m3(smat, td->smtx, totmat);
+ /* apply gpencil falloff */
+ if (t->options & CTX_GPENCIL_STROKES) {
+ bGPDstroke *gps = (bGPDstroke *)td->extra;
+ float sx = smat[0][0];
+ float sy = smat[1][1];
+ float sz = smat[2][2];
+
+ mul_m3_fl(smat, gps->runtime.multi_frame_falloff);
+ /* fix scale */
+ smat[0][0] = sx;
+ smat[1][1] = sy;
+ smat[2][2] = sz;
+ }
+
sub_v3_v3v3(vec, td->iloc, center);
mul_m3_v3(smat, vec);
@@ -4578,7 +4634,16 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
}
mul_m3_v3(td->smtx, tvec);
- mul_v3_fl(tvec, td->factor);
+
+ if (t->options & CTX_GPENCIL_STROKES) {
+ /* grease pencil multiframe falloff */
+ bGPDstroke *gps = (bGPDstroke *)td->extra;
+ mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff);
+ }
+ else {
+ /* proportional editing falloff */
+ mul_v3_fl(tvec, td->factor);
+ }
protectedTransBits(td->protectflag, tvec);
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 675441189b0..d3b7417c4dd 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -90,6 +90,7 @@
#include "BKE_editmesh.h"
#include "BKE_tracking.h"
#include "BKE_mask.h"
+#include "BKE_colortools.h"
#include "BIK_api.h"
@@ -3609,6 +3610,8 @@ static void posttrans_gpd_clean(bGPdata *gpd)
}
#endif
}
+ /* set cache flag to dirty */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
}
static void posttrans_mask_clean(Mask *mask)
@@ -8086,7 +8089,14 @@ void flushTransPaintCurve(TransInfo *t)
static void createTransGPencil(bContext *C, TransInfo *t)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C); \
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_FRAME_FALLOFF) != 0;
+
+ Object *obact = CTX_data_active_object(C);
bGPDlayer *gpl;
TransData *td = NULL;
float mtx[3][3], smtx[3][3];
@@ -8110,50 +8120,67 @@ static void createTransGPencil(bContext *C, TransInfo *t)
if (gpd == NULL)
return;
+ /* initialize falloff curve */
+ if (is_multiedit) {
+ curvemapping_initialize(ts->gp_sculpt.cur_falloff);
+ }
+
/* First Pass: Count the number of datapoints required for the strokes,
* (and additional info about the configuration - e.g. 2D/3D?)
*/
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)) {
- bGPDframe *gpf = gpl->actframe;
+ bGPDframe *gpf;
bGPDstroke *gps;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
- for (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;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
- continue;
- }
+ for (gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ for (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;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ continue;
+ }
- if (is_prop_edit) {
- /* Proportional Editing... */
- if (is_prop_edit_connected) {
- /* connected only - so only if selected */
- if (gps->flag & GP_STROKE_SELECT)
- tc->data_len += gps->totpoints;
- }
- else {
- /* everything goes - connection status doesn't matter */
- tc->data_len += gps->totpoints;
- }
- }
- else {
- /* only selected stroke points are considered */
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
-
- // TODO: 2D vs 3D?
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT)
- tc->data_len++;
+ if (is_prop_edit) {
+ /* Proportional Editing... */
+ if (is_prop_edit_connected) {
+ /* connected only - so only if selected */
+ if (gps->flag & GP_STROKE_SELECT)
+ tc->data_len += gps->totpoints;
+ }
+ else {
+ /* everything goes - connection status doesn't matter */
+ tc->data_len += gps->totpoints;
+ }
+ }
+ else {
+ /* only selected stroke points are considered */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ // TODO: 2D vs 3D?
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT)
+ tc->data_len++;
+ }
+ }
}
}
}
+ /* if not multiedit out of loop */
+ if (!is_multiedit) {
+ break;
+ }
}
}
}
@@ -8180,153 +8207,166 @@ static void createTransGPencil(bContext *C, TransInfo *t)
float diff_mat[4][4];
float inverse_diff_mat[4][4];
- /* calculate difference matrix if parent object */
- if (gpl->parent != NULL) {
- ED_gpencil_parent_location(gpl, diff_mat);
- /* undo matrix */
- invert_m4_m4(inverse_diff_mat, diff_mat);
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
}
+ /* init multiframe falloff options */
+ int f_init = 0;
+ int f_end = 0;
+
+ if (use_multiframe_falloff) {
+ BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
+ }
+
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ /* undo matrix */
+ invert_m4_m4(inverse_diff_mat, diff_mat);
/* Make a new frame to work on if the layer's frame and the current scene frame don't match up
* - This is useful when animating as it saves that "uh-oh" moment when you realize you've
* spent too much time editing the wrong frame...
*/
- if (gpf->framenum != cfra) {
+ // XXX: should this be allowed when framelock is enabled?
+ if ((gpf->framenum != cfra) && (!is_multiedit)) {
gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
/* in some weird situations (framelock enabled) return NULL */
if (gpf == NULL) {
continue;
}
+ if (!is_multiedit) {
+ init_gpf = gpf;
+ }
}
/* Loop over strokes, adding TransData for points as needed... */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- TransData *head = td;
- TransData *tail = td;
- bool stroke_ok;
-
- /* 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(gpl, gps) == false) {
- continue;
- }
- /* What we need to include depends on proportional editing settings... */
- if (is_prop_edit) {
- if (is_prop_edit_connected) {
- /* A) "Connected" - Only those in selected strokes */
- stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
- }
- else {
- /* B) All points, always */
- stroke_ok = true;
- }
- }
- else {
- /* C) Only selected points in selected strokes */
- stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
- }
-
- /* Do stroke... */
- if (stroke_ok && gps->totpoints) {
- bGPDspoint *pt;
- int i;
-
-#if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or is_prop_edit breaks */
- const float ninv = 1.0f / gps->totpoints;
- float center[3] = {0.0f};
-
- /* compute midpoint of stroke */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- madd_v3_v3v3fl(center, center, &pt->x, ninv);
+ for (gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+
+ /* if multiframe and falloff, recalculate and save value */
+ float falloff = 1.0f; /* by default no falloff */
+ if ((is_multiedit) && (use_multiframe_falloff)) {
+ /* Faloff depends on distance to active frame (relative to the overall frame range) */
+ falloff = BKE_gpencil_multiframe_falloff_calc(gpf, gpl->actframe->framenum,
+ f_init, f_end, ts->gp_sculpt.cur_falloff);
}
-#endif
- /* add all necessary points... */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- bool point_ok;
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ TransData *head = td;
+ TransData *tail = td;
+ bool stroke_ok;
- /* include point? */
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ continue;
+ }
+ /* What we need to include depends on proportional editing settings... */
if (is_prop_edit) {
- /* Always all points in strokes that get included */
- point_ok = true;
+ if (is_prop_edit_connected) {
+ /* A) "Connected" - Only those in selected strokes */
+ stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
+ }
+ else {
+ /* B) All points, always */
+ stroke_ok = true;
+ }
}
else {
- /* Only selected points in selected strokes */
- point_ok = (pt->flag & GP_SPOINT_SELECT) != 0;
+ /* C) Only selected points in selected strokes */
+ stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
}
- /* do point... */
- if (point_ok) {
- copy_v3_v3(td->iloc, &pt->x);
- copy_v3_v3(td->center, &pt->x); // XXX: what about t->around == local?
-
- td->loc = &pt->x;
-
- td->flag = 0;
+ /* Do stroke... */
+ if (stroke_ok && gps->totpoints) {
+ bGPDspoint *pt;
+ int i;
- if (pt->flag & GP_SPOINT_SELECT)
- td->flag |= TD_SELECTED;
-
- /* for other transform modes (e.g. shrink-fatten), need to additional data */
- if (t->mode == TFM_GPENCIL_SHRINKFATTEN) {
- td->val = &pt->pressure;
- td->ival = pt->pressure;
- }
+ /* save falloff factor */
+ gps->runtime.multi_frame_falloff = falloff;
- /* screenspace needs special matrices... */
- if ((gps->flag & (GP_STROKE_3DSPACE | GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) == 0) {
- /* screenspace */
- td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
+ /* add all necessary points... */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ bool point_ok;
- /* apply parent transformations */
- if (gpl->parent == NULL) {
- copy_m3_m4(td->smtx, t->persmat);
- copy_m3_m4(td->mtx, t->persinv);
- unit_m3(td->axismtx);
+ /* include point? */
+ if (is_prop_edit) {
+ /* Always all points in strokes that get included */
+ point_ok = true;
}
else {
- /* apply matrix transformation relative to parent */
- copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
- copy_m3_m4(td->mtx, diff_mat); /* display position */
- copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
- }
- }
- else {
- /* configure 2D dataspace points so that they don't play up... */
- if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) {
- td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
- // XXX: matrices may need to be different?
+ /* Only selected points in selected strokes */
+ point_ok = (pt->flag & GP_SPOINT_SELECT) != 0;
}
- /* apply parent transformations */
- if (gpl->parent == NULL) {
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- unit_m3(td->axismtx); // XXX?
- }
- else {
- /* apply matrix transformation relative to parent */
- copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
- copy_m3_m4(td->mtx, diff_mat); /* display position */
- copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
+ /* do point... */
+ if (point_ok) {
+ copy_v3_v3(td->iloc, &pt->x);
+ copy_v3_v3(td->center, &pt->x); // XXX: what about t->around == local?
+
+ td->loc = &pt->x;
+
+ td->flag = 0;
+
+ if (pt->flag & GP_SPOINT_SELECT)
+ td->flag |= TD_SELECTED;
+
+ /* for other transform modes (e.g. shrink-fatten), need to additional data
+ * but never for scale or mirror
+ */
+ if ((t->mode != TFM_RESIZE) && (t->mode != TFM_MIRROR)) {
+ td->val = &pt->pressure;
+ td->ival = pt->pressure;
+ }
+
+ /* screenspace needs special matrices... */
+ if ((gps->flag & (GP_STROKE_3DSPACE | GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) == 0) {
+ /* screenspace */
+ td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
+
+ /* apply matrix transformation relative to parent */
+ copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
+ copy_m3_m4(td->mtx, diff_mat); /* display position */
+ copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
+ }
+ else {
+ /* configure 2D dataspace points so that they don't play up... */
+ if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) {
+ td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
+ // XXX: matrices may need to be different?
+ }
+
+ /* apply parent transformations */
+ copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
+ copy_m3_m4(td->mtx, diff_mat); /* display position */
+ copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
+ }
+ /* Triangulation must be calculated again, so save the stroke for recalc function */
+ td->extra = gps;
+
+ /* save pointer to object */
+ td->ob = obact;
+
+ td++;
+ tail++;
}
}
- /* Triangulation must be calculated again, so save the stroke for recalc function */
- td->extra = gps;
- td++;
- tail++;
+ /* March over these points, and calculate the proportional editing distances */
+ if (is_prop_edit && (head != tail)) {
+ /* XXX: for now, we are similar enough that this works... */
+ calc_distanceCurveVerts(head, tail - 1);
+ }
}
}
-
- /* March over these points, and calculate the proportional editing distances */
- if (is_prop_edit && (head != tail)) {
- /* XXX: for now, we are similar enough that this works... */
- calc_distanceCurveVerts(head, tail - 1);
- }
+ }
+ /* if not multiedit out of loop */
+ if (!is_multiedit) {
+ break;
}
}
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 3618d57b3ed..a2377166dff 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -74,6 +74,7 @@
#include "BKE_armature.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
+#include "BKE_gpencil.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -105,6 +106,7 @@
#include "ED_curve.h" /* for curve_editnurbs */
#include "ED_clip.h"
#include "ED_screen.h"
+#include "ED_gpencil.h"
#include "WM_types.h"
#include "WM_api.h"
@@ -379,7 +381,8 @@ static void recalcData_actedit(TransInfo *t)
/* flush transform values back to actual coordinates */
flushTransIntFrameActionData(t);
}
- else {
+
+ if (ac.datatype != ANIMCONT_MASK) {
/* get animdata blocks visible in editor, assuming that these will be the ones where things changed */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -1311,7 +1314,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* GPencil editing context */
- if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
+ if (GPENCIL_ANY_MODE(gpd)) {
t->options |= CTX_GPENCIL_STROKES;
}
@@ -1823,6 +1826,21 @@ void calculateCenterCursor(TransInfo *t, float r_center[3])
}
r_center[2] = 0.0f;
}
+ else if (t->options & CTX_GPENCIL_STROKES) {
+ /* move cursor in local space */
+ TransData *td = NULL;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ float mat[3][3], imat[3][3];
+
+ td = tc->data;
+ Object *ob = td->ob;
+
+ sub_v3_v3v3(r_center, r_center, ob->obmat[3]);
+ copy_m3_m4(mat, ob->obmat);
+ invert_m3_m3(imat, mat);
+ mul_m3_v3(imat, r_center);
+ }
+ }
}
void calculateCenterCursor2D(TransInfo *t, float r_center[2])
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index cbc2b312512..3b5d7d5871a 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -604,6 +604,7 @@ int ED_transform_calc_gizmo_stats(
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obedit = CTX_data_edit_object(C);
View3D *v3d = sa->spacedata.first;
@@ -611,7 +612,7 @@ int ED_transform_calc_gizmo_stats(
Base *base;
Object *ob = OBACT(view_layer);
bGPdata *gpd = CTX_data_gpencil_data(C);
- const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
+ const bool is_gp_edit = GPENCIL_ANY_MODE(gpd);
int a, totsel = 0;
const int pivot_point = scene->toolsettings->transform_pivot_point;
@@ -728,10 +729,8 @@ int ED_transform_calc_gizmo_stats(
/* only editable and visible layers are considered */
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- /* calculate difference matrix if parent object */
- if (gpl->parent != NULL) {
- ED_gpencil_parent_location(gpl, diff_mat);
- }
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, ob, gpd, 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/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index a6e857c4a60..bc35e6e6b89 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -2280,7 +2280,12 @@ static short snapObject(
dist_px,
r_loc, r_no, r_index);
break;
-
+ case OB_GPENCIL:
+ retval = snapEmpty(
+ snapdata, ob, obmat,
+ dist_px,
+ r_loc, r_no, r_index);
+ break;
case OB_CAMERA:
retval = snapCamera(
sctx, snapdata, ob, obmat,
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 14592149579..7c1dc148dde 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -51,9 +51,12 @@
#include "BKE_screen.h"
#include "BKE_layer.h"
#include "BKE_undo_system.h"
+#include "BKE_workspace.h"
+#include "BKE_paint.h"
#include "ED_gpencil.h"
#include "ED_render.h"
+#include "ED_object.h"
#include "ED_screen.h"
#include "ED_undo.h"
@@ -110,6 +113,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
+ ScrArea *sa = CTX_wm_area(C);
/* undo during jobs are running can easily lead to freeing data using by jobs,
* or they can just lead to freezing job in some other cases */
@@ -122,6 +126,12 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
if (ED_gpencil_session_active()) {
return ED_undo_gpencil_step(C, step, undoname);
}
+ if (sa && (sa->spacetype == SPACE_VIEW3D)) {
+ Object *obact = CTX_data_active_object(C);
+ if (obact && (obact->type == OB_GPENCIL)) {
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ }
+ }
UndoStep *step_data_from_name = NULL;
int step_for_callback = step;
@@ -156,6 +166,23 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
else {
BKE_undosys_step_undo_compat_only(wm->undo_stack, C, step);
}
+
+ /* Set special modes for grease pencil */
+ if (sa && (sa->spacetype == SPACE_VIEW3D)) {
+ Object *obact = CTX_data_active_object(C);
+ if (obact && (obact->type == OB_GPENCIL)) {
+ /* set cursor */
+ if (ELEM(obact->mode, OB_MODE_GPENCIL_PAINT, OB_MODE_GPENCIL_SCULPT, OB_MODE_GPENCIL_WEIGHT)) {
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ }
+ else {
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ }
+ /* set workspace mode */
+ Base *basact = CTX_data_active_base(C);
+ ED_object_base_activate(C, basact);
+ }
+ }
}
/* App-Handlers (post). */
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
new file mode 100644
index 00000000000..5ad91d4e01b
--- /dev/null
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -0,0 +1,70 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# 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) 2018, Blender Foundation
+# All rights reserved.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ intern
+ ../blenkernel
+ ../blenlib
+ ../blenfont
+ ../depsgraph
+ ../makesdna
+ ../makesrna
+ ../bmesh
+ ../render/extern/include
+ ../../../intern/elbeem/extern
+ ../../../intern/guardedalloc
+ ../../../intern/eigen
+)
+
+set(INC_SYS
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+set(SRC
+ intern/MOD_gpencil_util.h
+
+ intern/MOD_gpencil_util.c
+ intern/MOD_gpencilnoise.c
+ intern/MOD_gpencilsubdiv.c
+ intern/MOD_gpencilsimplify.c
+ intern/MOD_gpencilthick.c
+ intern/MOD_gpenciltint.c
+ intern/MOD_gpencilcolor.c
+ intern/MOD_gpencilinstance.c
+ intern/MOD_gpencilbuild.c
+ intern/MOD_gpencilopacity.c
+ intern/MOD_gpencillattice.c
+ intern/MOD_gpencilmirror.c
+ intern/MOD_gpencilsmooth.c
+ intern/MOD_gpencilhook.c
+ intern/MOD_gpenciloffset.c
+
+ MOD_gpencil_modifiertypes.h
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+add_definitions(${GL_DEFINITIONS})
+
+blender_add_lib(bf_gpencil_modifiers "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
new file mode 100644
index 00000000000..ca941017ff9
--- /dev/null
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
@@ -0,0 +1,53 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * Contributor(s): Ben Batt
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file MOD_modifiertypes.h
+ * \ingroup modifiers
+ */
+
+#ifndef __MOD_GP_MODIFIERTYPES_H__
+#define __MOD_GP_MODIFIERTYPES_H__
+
+#include "BKE_gpencil_modifier.h"
+
+/* ****************** Type structures for all modifiers ****************** */
+
+extern GpencilModifierTypeInfo modifierType_Gpencil_None;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Noise;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Subdiv;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Simplify;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Thick;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Tint;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Color;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Instance;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Build;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Opacity;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Lattice;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Mirror;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Smooth;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Hook;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Offset;
+
+/* MOD_gpencil_util.c */
+void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]);
+
+#endif /* __MOD_GP_MODIFIERTYPES_H__ */
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
new file mode 100644
index 00000000000..97d28863095
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -0,0 +1,142 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencil_util.c
+ * \ingroup bke
+ */
+
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_math_color.h"
+#include "BLI_rand.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_global.h"
+#include "BKE_object.h"
+#include "BKE_lattice.h"
+#include "BKE_material.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_colortools.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+#include "MOD_gpencil_util.h"
+
+void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
+{
+#define INIT_GP_TYPE(typeName) (types[eGpencilModifierType_##typeName] = &modifierType_Gpencil_##typeName)
+ INIT_GP_TYPE(Noise);
+ INIT_GP_TYPE(Subdiv);
+ INIT_GP_TYPE(Simplify);
+ INIT_GP_TYPE(Thick);
+ INIT_GP_TYPE(Tint);
+ INIT_GP_TYPE(Color);
+ INIT_GP_TYPE(Instance);
+ INIT_GP_TYPE(Build);
+ INIT_GP_TYPE(Opacity);
+ INIT_GP_TYPE(Lattice);
+ INIT_GP_TYPE(Mirror);
+ INIT_GP_TYPE(Smooth);
+ INIT_GP_TYPE(Hook);
+ INIT_GP_TYPE(Offset);
+#undef INIT_GP_TYPE
+}
+
+/* verify if valid layer and pass index */
+bool is_stroke_affected_by_modifier(
+ Object *ob, char *mlayername, int mpassindex, int minpoints,
+ bGPDlayer *gpl, bGPDstroke *gps, bool inv1, bool inv2)
+{
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+
+ /* omit if filter by layer */
+ if (mlayername[0] != '\0') {
+ if (inv1 == false) {
+ if (!STREQ(mlayername, gpl->info)) {
+ return false;
+ }
+ }
+ else {
+ if (STREQ(mlayername, gpl->info)) {
+ return false;
+ }
+ }
+ }
+ /* verify pass */
+ if (mpassindex > 0) {
+ if (inv2 == false) {
+ if (gp_style->index != mpassindex) {
+ return false;
+ }
+ }
+ else {
+ if (gp_style->index == mpassindex) {
+ return false;
+ }
+ }
+ }
+ /* need to have a minimum number of points */
+ if ((minpoints > 0) && (gps->totpoints < minpoints)) {
+ return false;
+ }
+
+ return true;
+}
+
+/* verify if valid vertex group *and return weight */
+float get_modifier_point_weight(MDeformVert *dvert, int inverse, int vindex)
+{
+ float weight = 1.0f;
+
+ if (vindex >= 0) {
+ weight = BKE_gpencil_vgroup_use_index(dvert, vindex);
+ if ((weight >= 0.0f) && (inverse == 1)) {
+ return -1.0f;
+ }
+
+ if ((weight < 0.0f) && (inverse == 0)) {
+ return -1.0f;
+ }
+
+ /* if inverse, weight is always 1 */
+ if ((weight < 0.0f) && (inverse == 1)) {
+ return 1.0f;
+ }
+
+ }
+
+ return weight;
+}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
new file mode 100644
index 00000000000..50ac557042d
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -0,0 +1,47 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencil_util.h
+ * \ingroup modifiers
+ */
+
+
+#ifndef __MOD_GPENCIL_UTIL_H__
+#define __MOD_GPENCIL_UTIL_H__
+
+struct Object;
+struct bGPDlayer;
+struct bGPDstroke;
+struct MDeformVert;
+
+bool is_stroke_affected_by_modifier(
+ struct Object *ob, char *mlayername, int mpassindex, int minpoints,
+ bGPDlayer *gpl, bGPDstroke *gps, bool inv1, bool inv2);
+
+float get_modifier_point_weight(struct MDeformVert *dvert, int inverse, int vindex);
+
+#endif /* __MOD_GPENCIL_UTIL_H__ */
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
new file mode 100644
index 00000000000..6b959659a60
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
@@ -0,0 +1,558 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencilbuild.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.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 "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ BuildGpencilModifierData *gpmd = (BuildGpencilModifierData *)md;
+
+ /* We deliberately set this range to the half the default
+ * frame-range to have an immediate effect ot suggest use-cases
+ */
+ gpmd->start_frame = 1;
+ gpmd->end_frame = 125;
+
+ /* Init default length of each build effect - Nothing special */
+ gpmd->start_delay = 0.0f;
+ gpmd->length = 100.0f;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static bool dependsOnTime(GpencilModifierData *UNUSED(md))
+{
+ return true;
+}
+
+/* ******************************************** */
+/* Build Modifier - Stroke generation logic
+ *
+ * There are two modes for how the strokes are sequenced (at a macro-level):
+ * - Sequential Mode - Strokes appear/disappear one after the other. Only a single one changes at a time.
+ * - Concurrent Mode - Multiple strokes appear/disappear at once.
+ *
+ * Assumptions:
+ * - Stroke points are generally equally spaced. This implies that we can just add/remove points,
+ * without worrying about distances between them / adding extra interpolated points between
+ * an visible point and one about to be added/removed (or any similar tapering effects).
+
+ * - All strokes present are fully visible (i.e. we don't have to ignore any)
+ */
+
+/* Remove a particular stroke */
+static void clear_stroke(bGPDframe *gpf, bGPDstroke *gps)
+{
+ BLI_remlink(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
+}
+
+/* Clear all strokes in frame */
+static void gpf_clear_all_strokes(bGPDframe *gpf)
+{
+ bGPDstroke *gps, *gps_next;
+ for (gps = gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+ clear_stroke(gpf, gps);
+ }
+ BLI_listbase_clear(&gpf->strokes);
+}
+
+/* Reduce the number of points in the stroke
+ *
+ * Note: This won't be called if all points are present/removed
+ * TODO: Allow blending of growing/shrinking tip (e.g. for more gradual transitions)
+ */
+static void reduce_stroke_points(bGPDstroke *gps, const int num_points, const eBuildGpencil_Transition transition)
+{
+ bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * num_points, __func__);
+ MDeformVert *new_dvert = MEM_callocN(sizeof(MDeformVert) * num_points, __func__);
+
+ /* Which end should points be removed from */
+ // TODO: free stroke weights
+ switch (transition) {
+ case GP_BUILD_TRANSITION_GROW: /* Show in forward order = Remove ungrown-points from end of stroke */
+ case GP_BUILD_TRANSITION_SHRINK: /* Hide in reverse order = Remove dead-points from end of stroke */
+ {
+ /* copy over point data */
+ memcpy(new_points, gps->points, sizeof(bGPDspoint) * num_points);
+ memcpy(new_dvert, gps->dvert, sizeof(MDeformVert) * num_points);
+
+ /* free unused point weights */
+ for (int i = num_points; i < gps->totpoints; i++) {
+ MDeformVert *dvert = &gps->dvert[i];
+ BKE_gpencil_free_point_weights(dvert);
+ }
+
+ break;
+ }
+
+ /* Hide in forward order = Remove points from start of stroke */
+ case GP_BUILD_TRANSITION_FADE:
+ {
+ /* num_points is the number of points left after reducing.
+ * We need to know how many to remove
+ */
+ const int offset = gps->totpoints - num_points;
+
+ /* copy over point data */
+ memcpy(new_points, gps->points + offset, sizeof(bGPDspoint) * num_points);
+ memcpy(new_dvert, gps->dvert + offset, sizeof(MDeformVert) * num_points);
+
+ /* free unused weights */
+ for (int i = 0; i < offset; i++) {
+ MDeformVert *dvert = &gps->dvert[i];
+ BKE_gpencil_free_point_weights(dvert);
+ }
+
+ break;
+ }
+
+ default:
+ printf("ERROR: Unknown transition %d in %s()\n", (int)transition, __func__);
+ break;
+ }
+
+ /* replace stroke geometry */
+ MEM_SAFE_FREE(gps->points);
+ MEM_SAFE_FREE(gps->dvert);
+ gps->points = new_points;
+ gps->dvert = new_dvert;
+ gps->totpoints = num_points;
+
+ /* mark stroke as needing to have its geometry caches rebuilt */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+ MEM_SAFE_FREE(gps->triangles);
+}
+
+/* --------------------------------------------- */
+
+/* Stroke Data Table Entry - This represents one stroke being generated */
+typedef struct tStrokeBuildDetails {
+ bGPDstroke *gps;
+
+ /* Indices - first/last indices for the stroke's points (overall) */
+ size_t start_idx, end_idx;
+
+ /* Number of points - Cache for more convenient access */
+ int totpoints;
+} tStrokeBuildDetails;
+
+
+/* Sequential - Show strokes one after the other */
+static void build_sequential(BuildGpencilModifierData *mmd, bGPDframe *gpf, float fac)
+{
+ const size_t tot_strokes = BLI_listbase_count(&gpf->strokes);
+ bGPDstroke *gps;
+ size_t i;
+
+ /* 1) Compute proportion of time each stroke should occupy */
+ /* NOTE: This assumes that the total number of points won't overflow! */
+ tStrokeBuildDetails *table = MEM_callocN(sizeof(tStrokeBuildDetails) * tot_strokes, __func__);
+ size_t totpoints = 0;
+
+ /* 1.1) First pass - Tally up points */
+ for (gps = gpf->strokes.first, i = 0; gps; gps = gps->next, i++) {
+ tStrokeBuildDetails *cell = &table[i];
+
+ cell->gps = gps;
+ cell->totpoints = gps->totpoints;
+
+ totpoints += cell->totpoints;
+ }
+
+ /* 1.2) Second pass - Compute the overall indices for points */
+ for (i = 0; i < tot_strokes; i++) {
+ tStrokeBuildDetails *cell = &table[i];
+
+ if (i == 0) {
+ cell->start_idx = 0;
+ }
+ else {
+ cell->start_idx = (cell - 1)->end_idx;
+ }
+ cell->end_idx = cell->start_idx + cell->totpoints - 1;
+ }
+
+
+ /* 2) Determine the global indices for points that should be visible */
+ size_t first_visible = 0;
+ size_t last_visible = 0;
+
+ switch (mmd->transition) {
+ /* Show in forward order
+ * - As fac increases, the number of visible points increases
+ */
+ case GP_BUILD_TRANSITION_GROW:
+ first_visible = 0; /* always visible */
+ last_visible = (size_t)roundf(totpoints * fac);
+ break;
+
+ /* Hide in reverse order
+ * - As fac increases, the number of points visible at the end decreases
+ */
+ case GP_BUILD_TRANSITION_SHRINK:
+ first_visible = 0; /* always visible (until last point removed) */
+ last_visible = (size_t)(totpoints * (1.0f - fac));
+ break;
+
+ /* Hide in forward order
+ * - As fac increases, the early points start getting hidden
+ */
+ case GP_BUILD_TRANSITION_FADE:
+ first_visible = (size_t)(totpoints * fac);
+ last_visible = totpoints; /* i.e. visible until the end, unless first overlaps this */
+ break;
+ }
+
+
+ /* 3) Go through all strokes, deciding which to keep, and/or how much of each to keep */
+ for (i = 0; i < tot_strokes; i++) {
+ tStrokeBuildDetails *cell = &table[i];
+
+ /* Determine what portion of the stroke is visible */
+ if ((cell->end_idx < first_visible) || (cell->start_idx > last_visible)) {
+ /* Not visible at all - Either ended before */
+ clear_stroke(gpf, cell->gps);
+ }
+ else {
+ /* Some proportion of stroke is visible */
+ /* XXX: Will the transition settings still be valid now? */
+ if ((first_visible <= cell->start_idx) && (last_visible >= cell->end_idx)) {
+ /* Do nothing - whole stroke is visible */
+ }
+ else if (first_visible > cell->start_idx) {
+ /* Starts partway through this stroke */
+ int num_points = cell->end_idx - first_visible;
+ reduce_stroke_points(cell->gps, num_points, mmd->transition);
+ }
+ else {
+ /* Ends partway through this stroke */
+ int num_points = last_visible - cell->start_idx;
+ reduce_stroke_points(cell->gps, num_points, mmd->transition);
+ }
+ }
+ }
+
+ /* Free table */
+ MEM_freeN(table);
+}
+
+/* --------------------------------------------- */
+
+/* Concurrent - Show multiple strokes at once */
+// TODO: Allow random offsets to start times
+// TODO: Allow varying speeds? Scaling of progress?
+static void build_concurrent(BuildGpencilModifierData *mmd, bGPDframe *gpf, float fac)
+{
+ bGPDstroke *gps, *gps_next;
+ int max_points = 0;
+
+ const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW);
+
+ /* 1) Determine the longest stroke, to figure out when short strokes should start */
+ /* FIXME: A *really* long stroke here could dwarf everything else, causing bad timings */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (gps->totpoints > max_points) {
+ max_points = gps->totpoints;
+ }
+ }
+ if (max_points == 0) {
+ printf("ERROR: Strokes are all empty (GP Build Modifier: %s)\n", __func__);
+ return;
+ }
+
+ /* 2) For each stroke, determine how it should be handled */
+ for (gps = gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+
+ /* Relative Length of Stroke - Relative to the longest stroke,
+ * what proportion of the available time should this stroke use
+ */
+ const float relative_len = (float)gps->totpoints / (float)max_points;
+
+ /* Determine how many points should be left in the stroke */
+ int num_points = 0;
+
+ switch (mmd->time_alignment) {
+ case GP_BUILD_TIMEALIGN_START: /* all start on frame 1 */
+ {
+ /* Build effect occurs over when fac = 0, to fac = relative_len */
+ if (fac <= relative_len) {
+ /* Scale fac to fit relative_len */
+ /* FIXME: prevent potential div by zero (e.g. very short stroke vs one very long one) */
+ const float scaled_fac = fac / relative_len;
+
+ if (reverse) {
+ num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
+ }
+ else {
+ num_points = (int)roundf(scaled_fac * gps->totpoints);
+ }
+ }
+ else {
+ /* Build effect has ended */
+ if (reverse) {
+ num_points = 0;
+ }
+ else {
+ num_points = gps->totpoints;
+ }
+ }
+
+ break;
+ }
+ case GP_BUILD_TIMEALIGN_END: /* all end on same frame */
+ {
+ /* Build effect occurs over 1.0 - relative_len, to 1.0 (i.e. over the end of the range) */
+ const float start_fac = 1.0f - relative_len;
+
+ if (fac >= start_fac) {
+ /* FIXME: prevent potential div by zero (e.g. very short stroke vs one very long one) */
+ const float scaled_fac = (fac - start_fac) / relative_len;
+
+ if (reverse) {
+ num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
+ }
+ else {
+ num_points = (int)roundf(scaled_fac * gps->totpoints);
+ }
+ }
+ else {
+ /* Build effect hasn't started */
+ if (reverse) {
+ num_points = gps->totpoints;
+ }
+ else {
+ num_points = 0;
+ }
+ }
+
+ break;
+ }
+
+ /* TODO... */
+ }
+
+ /* Modify the stroke geometry */
+ if (num_points <= 0) {
+ /* Nothing Left - Delete the stroke */
+ clear_stroke(gpf, gps);
+ }
+ else if (num_points < gps->totpoints) {
+ /* Remove some points */
+ reduce_stroke_points(gps, num_points, mmd->transition);
+ }
+ }
+}
+
+/* --------------------------------------------- */
+
+/* Entry-point for Build Modifier */
+static void generateStrokes(
+ GpencilModifierData *md, Depsgraph *depsgraph,
+ Object *UNUSED(ob), 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) {
+ return;
+ }
+
+ /* Omit layer if filter by layer */
+ if (mmd->layername[0] != '\0') {
+ if ((mmd->flag & GP_BUILD_INVERT_LAYER) == 0) {
+ if (!STREQ(mmd->layername, gpl->info)) {
+ return;
+ }
+ }
+ else {
+ if (STREQ(mmd->layername, gpl->info)) {
+ return;
+ }
+ }
+ }
+
+ /* Early exit if outside of the frame range for this modifier
+ * (e.g. to have one forward, and one backwards modifier)
+ */
+ if (mmd->flag & GP_BUILD_RESTRICT_TIME) {
+ if ((ctime < mmd->start_frame) || (ctime > mmd->end_frame)) {
+ return;
+ }
+ }
+
+ /* Compute start and end frames for the animation effect
+ * 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;
+
+ if (gpf->next) {
+ /* Use the next frame or upper bound as end frame, whichever is lower/closer */
+ end_frame = MIN2(end_frame, gpf->next->framenum);
+ }
+
+
+ /* Early exit if current frame is outside start/end bounds */
+ /* NOTE: If we're beyond the next/prev frames (if existent), then we wouldn't have this problem anyway... */
+ if (ctime < start_frame) {
+ /* Before Start - Animation hasn't started. Display initial state. */
+ if (reverse) {
+ /* 1) Reverse = Start with all, end with nothing.
+ * ==> Do nothing (everything already present)
+ */
+ }
+ else {
+ /* 2) Forward Order = Start with nothing, end with the full frame.
+ * ==> Free all strokes, and return an empty frame
+ */
+ gpf_clear_all_strokes(gpf);
+ }
+
+ /* Early exit */
+ return;
+ }
+ else if (ctime >= end_frame) {
+ /* Past End - Animation finished. Display final result. */
+ if (reverse) {
+ /* 1) Reverse = Start with all, end with nothing.
+ * ==> Free all strokes, and return an empty frame
+ */
+ gpf_clear_all_strokes(gpf);
+ }
+ else {
+ /* 2) Forward Order = Start with nothing, end with the full frame.
+ * ==> Do Nothing (everything already present)
+ */
+ }
+
+ /* Early exit */
+ return;
+ }
+
+
+ /* 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) {
+ case GP_BUILD_MODE_SEQUENTIAL:
+ build_sequential(mmd, gpf, fac);
+ break;
+
+ case GP_BUILD_MODE_CONCURRENT:
+ build_concurrent(mmd, gpf, fac);
+ break;
+
+ default:
+ printf("Unsupported build mode (%d) for GP Build Modifier: '%s'\n", mmd->mode, mmd->modifier.name);
+ break;
+ }
+}
+
+/* ******************************************** */
+
+/* FIXME: Baking the Build Modifier is currently unsupported.
+ * Adding support for this is more complicated than for other
+ * modifiers, as to implement this, we'd have to add more frames,
+ * which would in turn break how the modifier functions.
+ */
+#if 0
+static void bakeModifier(
+ Main *bmain, const Depsgraph *UNUSED(depsgraph),
+ 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) {
+
+ }
+ }
+}
+#endif
+
+/* ******************************************** */
+
+GpencilModifierTypeInfo modifierType_Gpencil_Build = {
+ /* name */ "Build",
+ /* structName */ "BuildGpencilModifierData",
+ /* structSize */ sizeof(BuildGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ NULL,
+ /* generateStrokes */ generateStrokes,
+ /* bakeModifier */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ dependsOnTime,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
new file mode 100644
index 00000000000..af00b24715f
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
@@ -0,0 +1,178 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencilcolor.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math_color.h"
+#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_global.h"
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ ARRAY_SET_ITEMS(gpmd->hsv, 1.0f, 1.0f, 1.0f);
+ gpmd->layername[0] = '\0';
+ gpmd->flag |= GP_COLOR_CREATE_COLORS;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* color correction strokes */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+
+ ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md;
+ float hsv[3], factor[3];
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 1, gpl, gps,
+ mmd->flag & GP_COLOR_INVERT_LAYER, mmd->flag & GP_COLOR_INVERT_PASS))
+ {
+ return;
+ }
+
+ copy_v3_v3(factor, mmd->hsv);
+ add_v3_fl(factor, -1.0f);
+
+ 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);
+
+ 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);
+}
+
+static void bakeModifier(
+ Main *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 = give_current_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);
+
+ /* look for color */
+ if (mmd->flag & GP_TINT_CREATE_COLORS) {
+ 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);
+ assign_material(bmain, ob, newmat, ob->totcol, BKE_MAT_ASSIGN_EXISTING);
+
+ 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);
+ }
+ /* reasign color index */
+ int idx = BKE_object_material_slot_find_index(ob, newmat);
+ gps->mat_nr = idx - 1;
+ }
+ else {
+ /* reuse existing color */
+ copy_v4_v4(gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba);
+ copy_v4_v4(gp_style->fill_rgba, gps->runtime.tmp_fill_rgba);
+ }
+
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+ /* free hash buffers */
+ if (gh_color) {
+ BLI_ghash_free(gh_color, NULL, NULL);
+ gh_color = NULL;
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Color = {
+ /* name */ "Hue/Saturation",
+ /* structName */ "ColorGpencilModifierData",
+ /* structSize */ sizeof(ColorGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
new file mode 100644
index 00000000000..e036b6b78be
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
@@ -0,0 +1,355 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencilhook.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.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 "BLI_math.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_action.h"
+#include "BKE_context.h"
+#include "BKE_colortools.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_modifier.h"
+#include "BKE_library_query.h"
+#include "BKE_scene.h"
+#include "BKE_main.h"
+#include "BKE_layer.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"
+
+/* temp struct to hold data */
+struct GPHookData_cb {
+ struct CurveMapping *curfalloff;
+
+ char falloff_type;
+ float falloff;
+ float falloff_sq;
+ float fac_orig;
+
+ unsigned int use_falloff : 1;
+ unsigned int use_uniform : 1;
+
+ float cent[3];
+
+ float mat_uniform[3][3];
+ float mat[4][4];
+};
+
+static void initData(GpencilModifierData *md)
+{
+ HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->object = NULL;
+ gpmd->force = 0.5f;
+ gpmd->falloff_type = eGPHook_Falloff_Smooth;
+ gpmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (gpmd->curfalloff) {
+ curvemapping_initialize(gpmd->curfalloff);
+ }
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ HookGpencilModifierData *gmd = (HookGpencilModifierData *)md;
+ HookGpencilModifierData *tgmd = (HookGpencilModifierData *)target;
+
+ if (tgmd->curfalloff != NULL) {
+ curvemapping_free(tgmd->curfalloff);
+ tgmd->curfalloff = NULL;
+ }
+
+ BKE_gpencil_modifier_copyData_generic(md, target);
+
+ tgmd->curfalloff = curvemapping_copy(gmd->curfalloff);
+}
+
+/* calculate factor of fallof */
+static float gp_hook_falloff(const struct GPHookData_cb *tData, const float len_sq)
+{
+ BLI_assert(tData->falloff_sq);
+ if (len_sq > tData->falloff_sq) {
+ return 0.0f;
+ }
+ else if (len_sq > 0.0f) {
+ float fac;
+
+ if (tData->falloff_type == eGPHook_Falloff_Const) {
+ fac = 1.0f;
+ goto finally;
+ }
+ else if (tData->falloff_type == eGPHook_Falloff_InvSquare) {
+ /* avoid sqrt below */
+ fac = 1.0f - (len_sq / tData->falloff_sq);
+ goto finally;
+ }
+
+ fac = 1.0f - (sqrtf(len_sq) / tData->falloff);
+
+ switch (tData->falloff_type) {
+ case eGPHook_Falloff_Curve:
+ fac = curvemapping_evaluateF(tData->curfalloff, 0, fac);
+ break;
+ case eGPHook_Falloff_Sharp:
+ fac = fac * fac;
+ break;
+ case eGPHook_Falloff_Smooth:
+ fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
+ break;
+ case eGPHook_Falloff_Root:
+ fac = sqrtf(fac);
+ break;
+ case eGPHook_Falloff_Linear:
+ /* pass */
+ break;
+ case eGPHook_Falloff_Sphere:
+ fac = sqrtf(2 * fac - fac * fac);
+ break;
+ default:
+ fac = fac;
+ break;
+ }
+
+ finally:
+ return fac * tData->fac_orig;
+ }
+ else {
+ return tData->fac_orig;
+ }
+}
+
+/* apply point deformation */
+static void gp_hook_co_apply(struct GPHookData_cb *tData, float weight, bGPDspoint *pt)
+{
+ float fac;
+
+ if (tData->use_falloff) {
+ float len_sq;
+
+ if (tData->use_uniform) {
+ float co_uniform[3];
+ mul_v3_m3v3(co_uniform, tData->mat_uniform, &pt->x);
+ len_sq = len_squared_v3v3(tData->cent, co_uniform);
+ }
+ else {
+ len_sq = len_squared_v3v3(tData->cent, &pt->x);
+ }
+
+ fac = gp_hook_falloff(tData, len_sq);
+ }
+ else {
+ fac = tData->fac_orig;
+ }
+
+ if (fac) {
+ float co_tmp[3];
+ mul_v3_m4v3(co_tmp, tData->mat, &pt->x);
+ interp_v3_v3v3(&pt->x, &pt->x, co_tmp, fac * weight);
+ }
+}
+
+/* deform stroke */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+ if (!mmd->object) {
+ return;
+ }
+
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+ float weight = 1.0f;
+
+ bPoseChannel *pchan = BKE_pose_channel_find_name(mmd->object->pose, mmd->subtarget);
+ float dmat[4][4];
+ struct GPHookData_cb tData;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 3, gpl, gps,
+ mmd->flag & GP_HOOK_INVERT_LAYER, mmd->flag & GP_HOOK_INVERT_PASS))
+ {
+ return;
+ }
+
+ /* init struct */
+ tData.curfalloff = mmd->curfalloff;
+ tData.falloff_type = mmd->falloff_type;
+ tData.falloff = (mmd->falloff_type == eHook_Falloff_None) ? 0.0f : mmd->falloff;
+ tData.falloff_sq = SQUARE(tData.falloff);
+ tData.fac_orig = mmd->force;
+ tData.use_falloff = (tData.falloff_sq != 0.0f);
+ tData.use_uniform = (mmd->flag & GP_HOOK_UNIFORM_SPACE) != 0;
+
+ if (tData.use_uniform) {
+ copy_m3_m4(tData.mat_uniform, mmd->parentinv);
+ mul_v3_m3v3(tData.cent, tData.mat_uniform, mmd->cent);
+ }
+ else {
+ unit_m3(tData.mat_uniform);
+ copy_v3_v3(tData.cent, mmd->cent);
+ }
+
+ /* get world-space matrix of target, corrected for the space the verts are in */
+ if (mmd->subtarget[0] && pchan) {
+ /* bone target if there's a matching pose-channel */
+ mul_m4_m4m4(dmat, mmd->object->obmat, pchan->pose_mat);
+ }
+ else {
+ /* just object target */
+ copy_m4_m4(dmat, mmd->object->obmat);
+ }
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_series(tData.mat, ob->imat, dmat, mmd->parentinv);
+
+ /* loop points and apply deform */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ /* verify vertex group */
+ weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_HOOK_INVERT_VGROUP) == 0), vindex);
+ if (weight < 0) {
+ continue;
+ }
+ gp_hook_co_apply(&tData, weight, pt);
+ }
+}
+
+/* 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)
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ if (mmd->object == NULL)
+ return;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* apply hook effects on this frame
+ * NOTE: this assumes that we don't want hook animation on non-keyframed frames
+ */
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+
+ /* compute hook effects on this frame */
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+
+ /* return frame state and DB to original state */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+
+ if (mmd->curfalloff) {
+ curvemapping_free(mmd->curfalloff);
+ }
+}
+
+static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+
+ return !mmd->object;
+}
+
+static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ HookGpencilModifierData *lmd = (HookGpencilModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Hook Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
+}
+
+static void foreachObjectLink(
+ GpencilModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Hook = {
+ /* name */ "Hook",
+ /* structName */ "HookGpencilModifierData",
+ /* structSize */ sizeof(HookGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c
new file mode 100644
index 00000000000..64f3fbc4a95
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c
@@ -0,0 +1,360 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencilinstance.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+#include "BKE_layer.h"
+#include "BKE_collection.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ InstanceGpencilModifierData *gpmd = (InstanceGpencilModifierData *)md;
+ gpmd->count[0] = 1;
+ gpmd->count[1] = 1;
+ gpmd->count[2] = 1;
+ gpmd->offset[0] = 1.0f;
+ gpmd->offset[1] = 1.0f;
+ gpmd->offset[2] = 1.0f;
+ gpmd->shift[0] = 0.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;
+ gpmd->lock_axis |= GP_LOCKAXIS_X;
+ gpmd->flag |= GP_INSTANCE_MAKE_OBJECTS;
+
+ /* fill random values */
+ BLI_array_frand(gpmd->rnd, 20, 1);
+ gpmd->rnd[0] = 1;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* -------------------------------- */
+
+/* array modifier - generate geometry callback (for viewport/rendering) */
+/* TODO: How to skip this for the simplify options? --> !GP_SIMPLIFY_MODIF(ts, playing) */
+static void generate_geometry(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+{
+ InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)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;
+
+ bool *valid_strokes = MEM_callocN(sizeof(bool) * num_strokes, __func__);
+
+ 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->pass_index, 1, gpl, gps,
+ mmd->flag & GP_INSTANCE_INVERT_LAYER, mmd->flag & GP_INSTANCE_INVERT_PASS))
+ {
+ valid_strokes[idx] = true;
+ num_valid++;
+ }
+ }
+
+ /* 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");
+ }
+
+ MEM_SAFE_FREE(valid_strokes);
+ return;
+ }
+
+
+ /* Generate new instances of all existing strokes,
+ * keeping each instance together so they maintain
+ * the correct ordering relative to each other
+ */
+ for (int x = 0; x < mmd->count[0]; x++) {
+ for (int y = 0; y < mmd->count[1]; y++) {
+ for (int z = 0; z < mmd->count[2]; z++) {
+ /* original strokes are at index = 0,0,0 */
+ if ((x == 0) && (y == 0) && (z == 0)) {
+ continue;
+ }
+
+ /* Compute transforms for this instance */
+ const int elem_idx[3] = {x, y, z};
+ float mat[4][4];
+
+ BKE_gpencil_instance_modifier_instance_tfm(mmd, elem_idx, mat);
+
+ /* apply shift */
+ int sh = x;
+ if (mmd->lock_axis == GP_LOCKAXIS_Y) {
+ sh = y;
+ }
+ if (mmd->lock_axis == GP_LOCKAXIS_Z) {
+ sh = z;
+ }
+ madd_v3_v3fl(mat[3], mmd->shift, sh);
+
+ /* 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]) {
+ /* Duplicate stroke */
+ bGPDstroke *gps_dst = MEM_dupallocN(gps);
+ gps_dst->points = MEM_dupallocN(gps->points);
+ gps_dst->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, gps_dst);
+
+ gps_dst->triangles = MEM_dupallocN(gps->triangles);
+
+ /* Move points */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps_dst->points[i];
+ mul_m4_v3(mat, &pt->x);
+ }
+
+ /* Add new stroke to cache, to be added to the frame once
+ * all duplicates have been made
+ */
+ BLI_addtail(&stroke_cache, gps_dst);
+ }
+ }
+ }
+ }
+ }
+
+ /* merge newly created stroke instances back into the main stroke list */
+ BLI_movelisttolist(&gpf->strokes, &stroke_cache);
+
+ /* free temp data */
+ MEM_SAFE_FREE(valid_strokes);
+}
+
+/* bakeModifier - "Bake to Data" Mode */
+static void bakeModifierGP_strokes(
+ Depsgraph *depsgraph,
+ 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);
+ }
+ }
+}
+
+/* -------------------------------- */
+
+/* helper to create a new object */
+static Object *array_instance_add_ob_copy(Main *bmain, Scene *scene, Object *from_ob)
+{
+ Object *ob;
+
+ ob = BKE_object_copy(bmain, from_ob);
+ BKE_collection_object_add_from(bmain, scene, from_ob, ob);
+
+ zero_v3(ob->loc);
+ zero_v3(ob->rot);
+
+ DEG_id_type_tag(bmain, ID_OB);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&scene->id, 0);
+
+ return ob;
+}
+
+/* bakeModifier - "Make Objects" Mode */
+static void bakeModifierGP_objects(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob)
+{
+ InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ /* reset random */
+ mmd->rnd[0] = 1;
+
+ /* generate instances as objects */
+ for (int x = 0; x < mmd->count[0]; x++) {
+ for (int y = 0; y < mmd->count[1]; y++) {
+ for (int z = 0; z < mmd->count[2]; z++) {
+ Object *newob;
+ GpencilModifierData *fmd;
+
+ const int elem_idx[3] = {x, y, z};
+ float mat[4][4], finalmat[4][4];
+ int sh;
+
+ /* original strokes are at index = 0,0,0 */
+ if ((x == 0) && (y == 0) && (z == 0)) {
+ continue;
+ }
+
+ /* compute transform for instance */
+ BKE_gpencil_instance_modifier_instance_tfm(mmd, elem_idx, mat);
+ mul_m4_m4m4(finalmat, ob->obmat, mat);
+
+ /* moves to new origin */
+ sh = x;
+ if (mmd->lock_axis == GP_LOCKAXIS_Y) {
+ sh = y;
+ }
+ if (mmd->lock_axis == GP_LOCKAXIS_Z) {
+ sh = z;
+ }
+ madd_v3_v3fl(finalmat[3], mmd->shift, sh);
+
+ /* Create a new object
+ *
+ * NOTE: Copies share the same original GP datablock
+ * Artists can later user make_single_user on these
+ * to make them unique (if necessary), without too
+ * much extra memory usage.
+ */
+ newob = array_instance_add_ob_copy(bmain, scene, ob);
+
+ /* remove array on destination object */
+ fmd = (GpencilModifierData *)BLI_findstring(&newob->greasepencil_modifiers, md->name, offsetof(GpencilModifierData, name));
+ if (fmd) {
+ BLI_remlink(&newob->greasepencil_modifiers, fmd);
+ BKE_gpencil_modifier_free(fmd);
+ }
+
+ /* copy transforms to destination object */
+ copy_m4_m4(newob->obmat, finalmat);
+
+ copy_v3_v3(newob->loc, finalmat[3]);
+ mat4_to_eul(newob->rot, finalmat);
+ mat4_to_size(newob->size, finalmat);
+ }
+ }
+ }
+}
+
+/* -------------------------------- */
+
+/* Generic "generateStrokes" callback */
+static void generateStrokes(
+ GpencilModifierData *md, Depsgraph *depsgraph,
+ Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+{
+ InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md;
+
+ /* When the "make_objects" flag is set, this modifier is handled as part of the
+ * draw engine instead. The main benefit is that the instances won't suffer from
+ * z-ordering problems.
+ *
+ * FIXME: Ultimately, the draw-engine hack here shouldn't be necessary, but until
+ * we find a better fix to the z-ordering problems, it's better to have
+ * working functionality
+ */
+ if ((mmd->flag & GP_INSTANCE_MAKE_OBJECTS) == 0) {
+ generate_geometry(md, depsgraph, ob, gpl, gpf);
+ }
+}
+
+/* Generic "bakeModifier" callback */
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md;
+
+ /* Create new objects or add all to current datablock.
+ * Sometimes it's useful to have the option to do either of these...
+ */
+ if (mmd->flag & GP_INSTANCE_MAKE_OBJECTS) {
+ bakeModifierGP_objects(bmain, depsgraph, md, ob);
+ }
+ else {
+ bakeModifierGP_strokes(depsgraph, md, ob);
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Instance = {
+ /* name */ "Instance",
+ /* structName */ "InstanceGpencilModifierData",
+ /* structSize */ sizeof(InstanceGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ NULL,
+ /* generateStrokes */ generateStrokes,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
new file mode 100644
index 00000000000..944e787020e
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
@@ -0,0 +1,213 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencillattice.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.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 "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_modifier.h"
+#include "BKE_lattice.h"
+#include "BKE_library_query.h"
+#include "BKE_scene.h"
+#include "BKE_main.h"
+#include "BKE_layer.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)
+{
+ LatticeGpencilModifierData *gpmd = (LatticeGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->object = NULL;
+ gpmd->cache_data = NULL;
+ gpmd->strength = 1.0f;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+ float weight = 1.0f;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 3, gpl, gps,
+ mmd->flag & GP_LATTICE_INVERT_LAYER, mmd->flag & GP_LATTICE_INVERT_PASS))
+ {
+ return;
+ }
+
+ if (mmd->cache_data == NULL) {
+ return;
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ /* verify vertex group */
+ weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_LATTICE_INVERT_VGROUP) == 0), vindex);
+ if (weight < 0) {
+ continue;
+ }
+
+ calc_latt_deform((struct LatticeDeformData *)mmd->cache_data, &pt->x, mmd->strength * weight);
+ }
+}
+
+/* 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)
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ struct LatticeDeformData *ldata = NULL;
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ if (mmd->object == NULL)
+ return;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* apply lattice effects on this frame
+ * NOTE: this assumes that we don't want lattice animation on non-keyframed frames
+ */
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+
+ /* recalculate lattice data */
+ BKE_gpencil_lattice_init(ob);
+
+ /* compute lattice effects on this frame */
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+
+ /* free lingering data */
+ ldata = (struct LatticeDeformData *)mmd->cache_data;
+ if (ldata) {
+ end_latt_deform(ldata);
+ mmd->cache_data = NULL;
+ }
+
+ /* return frame state and DB to original state */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ struct LatticeDeformData *ldata = (struct LatticeDeformData *)mmd->cache_data;
+ /* free deform data */
+ if (ldata) {
+ end_latt_deform(ldata);
+ }
+}
+
+static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+
+ return !mmd->object;
+}
+
+static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ LatticeGpencilModifierData *lmd = (LatticeGpencilModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Lattice Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier");
+}
+
+static void foreachObjectLink(
+ GpencilModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Lattice = {
+ /* name */ "Lattice",
+ /* structName */ "LatticeGpencilModifierData",
+ /* structSize */ sizeof(LatticeGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_Single | eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
new file mode 100644
index 00000000000..9b5186755d6
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
@@ -0,0 +1,239 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencilmirror.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.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 "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_modifier.h"
+#include "BKE_library_query.h"
+#include "BKE_scene.h"
+#include "BKE_main.h"
+#include "BKE_layer.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)
+{
+ MirrorGpencilModifierData *gpmd = (MirrorGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->object = NULL;
+ gpmd->flag |= GP_MIRROR_AXIS_X;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static void clip_stroke(MirrorGpencilModifierData *mmd, bGPDstroke *gps)
+{
+ int i;
+ bGPDspoint *pt;
+ float fpt[3];
+ if ((mmd->flag & GP_MIRROR_CLIPPING) == 0) {
+ return;
+ }
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ copy_v3_v3(fpt, &pt->x);
+ for (int xi = 0; xi < 3; ++xi) {
+ if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) {
+ if (fpt[xi] >= 0.0f) {
+ fpt[xi] = 0.0f;
+ }
+ }
+ }
+ copy_v3_v3(&pt->x, fpt);
+ }
+
+}
+
+static void update_position(Object *ob, MirrorGpencilModifierData *mmd, bGPDstroke *gps, int axis)
+{
+ int i;
+ bGPDspoint *pt;
+ float factor[3] = { 1.0f, 1.0f, 1.0f };
+ factor[axis] = -1.0f;
+
+ float clear[3] = { 0.0f, 0.0f, 0.0f };
+ clear[axis] = 1.0f;
+
+ float origin[3];
+ float mirror_origin[3];
+
+ copy_v3_v3(origin, ob->loc);
+ /* only works with current axis */
+ mul_v3_v3(origin, clear);
+ zero_v3(mirror_origin);
+
+ if (mmd->object) {
+ copy_v3_v3(mirror_origin, mmd->object->loc);
+ mul_v3_v3(mirror_origin, clear);
+ sub_v3_v3(origin, mirror_origin);
+ }
+ /* clear other axis */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ add_v3_v3(&pt->x, origin);
+ mul_v3_v3(&pt->x, factor);
+ add_v3_v3(&pt->x, mirror_origin);
+ }
+
+}
+
+/* Generic "generateStrokes" callback */
+static void generateStrokes(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+{
+ MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+ bGPDstroke *gps, *gps_new = NULL;
+ int tot_strokes;
+ int i;
+
+ /* count strokes to avoid infinite loop after adding new strokes to tail of listbase */
+ tot_strokes = BLI_listbase_count(&gpf->strokes);
+
+ for (i = 0, gps = gpf->strokes.first; i < tot_strokes; i++, gps = gps->next) {
+ if (is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 1, gpl, gps,
+ mmd->flag & GP_MIRROR_INVERT_LAYER, mmd->flag & GP_MIRROR_INVERT_PASS))
+ {
+ /* check each axis for mirroring */
+ for (int xi = 0; xi < 3; ++xi) {
+ if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) {
+ /* clip before duplicate */
+ clip_stroke(mmd, gps);
+
+ gps_new = BKE_gpencil_stroke_duplicate(gps);
+ update_position(ob, mmd, gps_new, xi);
+ BLI_addtail(&gpf->strokes, gps_new);
+ }
+ }
+ }
+ }
+}
+
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ if (mmd->object == NULL)
+ return;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* 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);
+ }
+ }
+
+ /* return frame state and DB to original state */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+static bool isDisabled(GpencilModifierData *UNUSED(md), int UNUSED(userRenderParams))
+{
+ //MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+
+ return false;
+}
+
+static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ MirrorGpencilModifierData *lmd = (MirrorGpencilModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Mirror Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
+}
+
+static void foreachObjectLink(
+ GpencilModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Mirror = {
+ /* name */ "Mirror",
+ /* structName */ "MirrorGpencilModifierData",
+ /* structSize */ sizeof(MirrorGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ NULL,
+ /* generateStrokes */ generateStrokes,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
new file mode 100644
index 00000000000..37c8bf0b0f0
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
@@ -0,0 +1,285 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencilnoise.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_rand.h"
+
+#include "PIL_time.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_context.h"
+#include "BKE_global.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->flag |= GP_NOISE_MOD_LOCATION;
+ gpmd->flag |= GP_NOISE_FULL_STROKE;
+ gpmd->flag |= GP_NOISE_USE_RANDOM;
+ gpmd->factor = 0.5f;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->step = 1;
+ gpmd->scene_frame = -999999;
+ gpmd->gp_frame = -999999;
+
+ gpmd->vrand1 = 1.0;
+ gpmd->vrand2 = 1.0;
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md;
+
+ if (mmd->rng != NULL) {
+ BLI_rng_free(mmd->rng);
+ }
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static bool dependsOnTime(GpencilModifierData *md)
+{
+ NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md;
+ return (mmd->flag & GP_NOISE_USE_RANDOM) != 0;
+}
+
+/* aply noise effect based on stroke direction */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *depsgraph,
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md;
+ bGPDspoint *pt0, *pt1;
+ MDeformVert *dvert;
+ float shift, vran, vdir;
+ float normal[3];
+ float vec1[3], vec2[3];
+#if 0
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+#endif
+ int sc_frame = 0;
+ int sc_diff = 0;
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+ float weight = 1.0f;
+
+ /* Random generator, only init once. */
+ if (mmd->rng == NULL) {
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= GET_UINT_FROM_POINTER(mmd);
+ mmd->rng = BLI_rng_new(rng_seed);
+ }
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 3, gpl, gps,
+ mmd->flag & GP_NOISE_INVERT_LAYER, mmd->flag & GP_NOISE_INVERT_PASS))
+ {
+ return;
+ }
+
+ sc_frame = (int)DEG_get_ctime(depsgraph);
+
+ zero_v3(vec2);
+
+ /* calculate stroke normal*/
+ BKE_gpencil_stroke_normal(gps, normal);
+
+ /* 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;
+ }
+
+ /* last point is special */
+ if (i == gps->totpoints) {
+ dvert = &gps->dvert[i - 2];
+ pt0 = &gps->points[i - 2];
+ pt1 = &gps->points[i - 1];
+ }
+ else {
+ dvert = &gps->dvert[i - 1];
+ pt0 = &gps->points[i - 1];
+ pt1 = &gps->points[i];
+
+ }
+
+ /* verify vertex group */
+ weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_NOISE_INVERT_VGROUP) == 0), vindex);
+ if (weight < 0) {
+ continue;
+ }
+
+ /* initial vector (p0 -> p1) */
+ sub_v3_v3v3(vec1, &pt1->x, &pt0->x);
+ 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) {
+ sc_diff = abs(mmd->scene_frame - sc_frame);
+ /* only recalc if the gp frame change or the number of scene frames is bigger than step */
+ if ((!gpl->actframe) || (mmd->gp_frame != gpl->actframe->framenum) ||
+ (sc_diff >= mmd->step))
+ {
+ vran = mmd->vrand1 = BLI_rng_get_float(mmd->rng);
+ vdir = mmd->vrand2 = BLI_rng_get_float(mmd->rng);
+ mmd->gp_frame = gpl->actframe->framenum;
+ mmd->scene_frame = sc_frame;
+ }
+ else {
+ vran = mmd->vrand1;
+ if (mmd->flag & GP_NOISE_FULL_STROKE) {
+ vdir = mmd->vrand2;
+ }
+ else {
+ int f = (mmd->vrand2 * 10.0f) + i;
+ vdir = f % 2;
+ }
+ }
+ }
+ else {
+ vran = 1.0f;
+ if (mmd->flag & GP_NOISE_FULL_STROKE) {
+ vdir = gps->totpoints % 2;
+ }
+ else {
+ vdir = i % 2;
+ }
+ mmd->gp_frame = -999999;
+ }
+
+ /* 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);
+ }
+
+ /* apply randomness to thickness */
+ if (mmd->flag & GP_NOISE_MOD_THICKNESS) {
+ if (vdir > 0.5f) {
+ pt1->pressure -= pt1->pressure * vran * mmd->factor;
+ }
+ else {
+ pt1->pressure += pt1->pressure * vran * mmd->factor;
+ }
+ CLAMP_MIN(pt1->pressure, GPENCIL_STRENGTH_MIN);
+ }
+
+ /* apply randomness to color strength */
+ if (mmd->flag & GP_NOISE_MOD_STRENGTH) {
+ if (vdir > 0.5f) {
+ pt1->strength -= pt1->strength * vran * mmd->factor;
+ }
+ else {
+ pt1->strength += pt1->strength * vran * mmd->factor;
+ }
+ 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;
+ }
+ else {
+ pt1->uv_rot += pt1->uv_rot * vran * mmd->factor;
+ }
+ CLAMP(pt1->uv_rot, -M_PI_2, M_PI_2);
+ }
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ 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) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Noise = {
+ /* name */ "Noise",
+ /* structName */ "NoiseGpencilModifierData",
+ /* structSize */ sizeof(NoiseGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ dependsOnTime,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
new file mode 100644
index 00000000000..8a96c705f08
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
@@ -0,0 +1,143 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpenciloffset.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.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 "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ OffsetGpencilModifierData *gpmd = (OffsetGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ ARRAY_SET_ITEMS(gpmd->loc, 0.0f, 0.0f, 0.0f);
+ ARRAY_SET_ITEMS(gpmd->rot, 0.0f, 0.0f, 0.0f);
+ ARRAY_SET_ITEMS(gpmd->scale, 0.0f, 0.0f, 0.0f);
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* change stroke offsetness */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ OffsetGpencilModifierData *mmd = (OffsetGpencilModifierData *)md;
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+
+ float mat[4][4];
+ float loc[3], rot[3], scale[3];
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 1, gpl, gps,
+ mmd->flag & GP_OFFSET_INVERT_LAYER, mmd->flag & GP_OFFSET_INVERT_PASS))
+ {
+ return;
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ /* verify vertex group */
+ float weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_OFFSET_INVERT_VGROUP) == 0), vindex);
+ if (weight < 0) {
+ continue;
+ }
+ /* calculate matrix */
+ mul_v3_v3fl(loc, mmd->loc, weight);
+ mul_v3_v3fl(rot, mmd->rot, weight);
+ mul_v3_v3fl(scale, mmd->scale, weight);
+ add_v3_fl(scale, 1.0);
+ loc_eul_size_to_mat4(mat, loc, rot, scale);
+
+ mul_m4_v3(mat, &pt->x);
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ 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) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Offset = {
+ /* name */ "Offset",
+ /* structName */ "OffsetGpencilModifierData",
+ /* structSize */ sizeof(OffsetGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
new file mode 100644
index 00000000000..bdd651a69fc
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
@@ -0,0 +1,171 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencilopacity.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.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_context.h"
+#include "BKE_deform.h"
+#include "BKE_material.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->factor = 1.0f;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* opacity strokes */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md;
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+
+ if (!is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, 3, gpl, gps,
+ mmd->flag & GP_OPACITY_INVERT_LAYER, mmd->flag & GP_OPACITY_INVERT_PASS))
+ {
+ return;
+ }
+
+ gp_style->fill_rgba[3]*= mmd->factor;
+
+ /* if factor is > 1, then force opacity */
+ if (mmd->factor > 1.0f) {
+ gp_style->stroke_rgba[3] += mmd->factor - 1.0f;
+ if (gp_style->fill_rgba[3] > 1e-5) {
+ gp_style->fill_rgba[3] += mmd->factor - 1.0f;
+ }
+ }
+
+ CLAMP(gp_style->stroke_rgba[3], 0.0f, 1.0f);
+ CLAMP(gp_style->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];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ /* verify vertex group */
+ float weight = get_modifier_point_weight(dvert, (!(mmd->flag & GP_OPACITY_INVERT_VGROUP) == 0), vindex);
+ if (weight < 0) {
+ pt->strength += mmd->factor - 1.0f;
+ }
+ else {
+ pt->strength += (mmd->factor - 1.0f) * weight;
+ }
+ CLAMP(pt->strength, 0.0f, 1.0f);
+ }
+ }
+ else {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ /* verify vertex group */
+ if (mmd->vgname == NULL) {
+ pt->strength *= mmd->factor;
+ }
+ else {
+ float weight = get_modifier_point_weight(dvert, (!(mmd->flag & GP_OPACITY_INVERT_VGROUP) == 0), vindex);
+ if (weight >= 0) {
+ pt->strength *= mmd->factor * weight;
+ }
+ }
+ CLAMP(pt->strength, 0.0f, 1.0f);
+ }
+ }
+
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ 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) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Opacity = {
+ /* name */ "Opacity",
+ /* structName */ "OpacityGpencilModifierData",
+ /* structSize */ sizeof(OpacityGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
new file mode 100644
index 00000000000..f0400e39b73
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
@@ -0,0 +1,123 @@
+/* ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencilsimplify.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_vec_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ SimplifyGpencilModifierData *gpmd = (SimplifyGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->step = 1;
+ gpmd->factor = 0.0f;
+ gpmd->layername[0] = '\0';
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ SimplifyGpencilModifierData *mmd = (SimplifyGpencilModifierData *)md;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 4, gpl, gps,
+ mmd->flag & GP_SIMPLIFY_INVERT_LAYER, mmd->flag & GP_SIMPLIFY_INVERT_PASS))
+ {
+ return;
+ }
+
+ if (mmd->mode == GP_SIMPLIFY_FIXED) {
+ for (int i = 0; i < mmd->step; i++) {
+ BKE_gpencil_simplify_fixed(gps);
+ }
+ }
+ else {
+ /* simplify stroke using Ramer-Douglas-Peucker algorithm */
+ BKE_gpencil_simplify_stroke(gps, mmd->factor);
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ 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) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Simplify = {
+ /* name */ "Simplify",
+ /* structName */ "SimplifyGpencilModifierData",
+ /* structSize */ sizeof(SimplifyGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
new file mode 100644
index 00000000000..b83c8ed98b1
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
@@ -0,0 +1,152 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencilsmooth.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->flag |= GP_SMOOTH_MOD_LOCATION;
+ gpmd->factor = 0.5f;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->step = 1;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* aply smooth effect based on stroke direction */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ SmoothGpencilModifierData *mmd = (SmoothGpencilModifierData *)md;
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+ float weight = 1.0f;
+ float val;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 3, gpl, gps,
+ mmd->flag & GP_SMOOTH_INVERT_LAYER, mmd->flag & GP_SMOOTH_INVERT_PASS))
+ {
+ return;
+ }
+
+ /* smooth stroke */
+ if (mmd->factor > 0.0f) {
+ for (int r = 0; r < mmd->step; r++) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ // bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ /* verify vertex group */
+ weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_SMOOTH_INVERT_VGROUP) == 0), vindex);
+ if (weight < 0) {
+ continue;
+ }
+
+ val = mmd->factor * weight;
+ /* perform smoothing */
+ if (mmd->flag & GP_SMOOTH_MOD_LOCATION) {
+ BKE_gpencil_smooth_stroke(gps, i, val);
+ }
+ if (mmd->flag & GP_SMOOTH_MOD_STRENGTH) {
+ BKE_gpencil_smooth_stroke_strength(gps, i, val);
+ }
+ if ((mmd->flag & GP_SMOOTH_MOD_THICKNESS) && (val > 0)) {
+ /* thickness need to repeat process several times */
+ for (int r2 = 0; r2 < r * 10; r2++) {
+ BKE_gpencil_smooth_stroke_thickness(gps, i, val);
+ }
+ }
+ if (mmd->flag & GP_SMOOTH_MOD_UV) {
+ BKE_gpencil_smooth_stroke_uv(gps, i, val);
+ }
+ }
+ }
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ 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) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Smooth = {
+ /* name */ "Smooth",
+ /* structName */ "SmoothGpencilModifierData",
+ /* structSize */ sizeof(SmoothGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
new file mode 100644
index 00000000000..6fe9c34c06b
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
@@ -0,0 +1,193 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencilsubdiv.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.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 "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ SubdivGpencilModifierData *gpmd = (SubdivGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->level = 1;
+ gpmd->layername[0] = '\0';
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* subdivide stroke to get more control points */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md;
+ bGPDspoint *temp_points;
+ int totnewpoints, oldtotpoints;
+ int i2;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 3, gpl, gps,
+ mmd->flag & GP_SUBDIV_INVERT_LAYER, mmd->flag & GP_SUBDIV_INVERT_PASS))
+ {
+ return;
+ }
+
+ /* loop as many times as levels */
+ for (int s = 0; s < mmd->level; s++) {
+ totnewpoints = gps->totpoints - 1;
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
+
+ /* resize the points arrys */
+ gps->totpoints += totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* move points from last to first to new place */
+ i2 = gps->totpoints - 1;
+ for (int i = oldtotpoints - 1; i > 0; i--) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ MDeformVert *dvert = &gps->dvert[i];
+ MDeformVert *dvert_final = &gps->dvert[i2];
+
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = dvert->dw;
+ i2 -= 2;
+ }
+ /* interpolate mid points */
+ i2 = 1;
+ for (int i = 0; i < oldtotpoints - 1; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i2];
+ MDeformVert *dvert_final = &gps->dvert[i2];
+
+ /* add a half way point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ 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);
+ pt_final->time = interpf(pt->time, next->time, 0.5f);
+
+ dvert_final->totweight = 0;
+ dvert_final->dw = NULL;
+ i2 += 2;
+ }
+
+ MEM_SAFE_FREE(temp_points);
+
+ /* move points to smooth stroke (not simple flag )*/
+ if ((mmd->flag & GP_SUBDIV_SIMPLE) == 0) {
+ /* duplicate points in a temp area with the new subdivide data */
+ temp_points = MEM_dupallocN(gps->points);
+
+ /* extreme points are not changed */
+ for (int i = 0; i < gps->totpoints - 2; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i + 1];
+
+ /* move point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ }
+ /* free temp memory */
+ MEM_SAFE_FREE(temp_points);
+ }
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ 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) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = {
+ /* name */ "Subdivision",
+ /* structName */ "SubdivGpencilModifierData",
+ /* structSize */ sizeof(SubdivGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
new file mode 100644
index 00000000000..118cc33255f
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
@@ -0,0 +1,171 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpencilthick.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.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 "BLI_utildefines.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->thickness = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->curve_thickness = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (gpmd->curve_thickness) {
+ curvemapping_initialize(gpmd->curve_thickness);
+ }
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
+
+ if (gpmd->curve_thickness) {
+ curvemapping_free(gpmd->curve_thickness);
+ }
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ ThickGpencilModifierData *gmd = (ThickGpencilModifierData *)md;
+ ThickGpencilModifierData *tgmd = (ThickGpencilModifierData *)target;
+
+ if (tgmd->curve_thickness != NULL) {
+ curvemapping_free(tgmd->curve_thickness);
+ tgmd->curve_thickness = NULL;
+ }
+
+ BKE_gpencil_modifier_copyData_generic(md, target);
+
+ tgmd->curve_thickness = curvemapping_copy(gmd->curve_thickness);
+}
+
+/* change stroke thickness */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ ThickGpencilModifierData *mmd = (ThickGpencilModifierData *)md;
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 3, gpl, gps,
+ mmd->flag & GP_THICK_INVERT_LAYER, mmd->flag & GP_THICK_INVERT_PASS))
+ {
+ return;
+ }
+
+ /* if normalize, set stroke thickness */
+ if (mmd->flag & GP_THICK_NORMALIZE) {
+ gps->thickness = mmd->thickness;
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+ float curvef = 1.0f;
+ /* verify vertex group */
+ float weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_THICK_INVERT_VGROUP) == 0), vindex);
+ if (weight < 0) {
+ continue;
+ }
+
+ if (mmd->flag & GP_THICK_NORMALIZE) {
+ pt->pressure = 1.0f;
+ }
+ else {
+ if ((mmd->flag & GP_THICK_CUSTOM_CURVE) && (mmd->curve_thickness)) {
+ /* normalize value to evaluate curve */
+ float value = (float)i / (gps->totpoints - 1);
+ curvef = curvemapping_evaluateF(mmd->curve_thickness, 0, value);
+ }
+
+ pt->pressure += mmd->thickness * weight * curvef;
+ CLAMP(pt->strength, 0.0f, 1.0f);
+ }
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ 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) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Thick = {
+ /* name */ "Thickness",
+ /* structName */ "ThickGpencilModifierData",
+ /* structSize */ sizeof(ThickGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
new file mode 100644
index 00000000000..9d1e9eccb8c
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
@@ -0,0 +1,186 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_gpenciltint.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_material.h"
+#include "BKE_main.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->factor = 0.5f;
+ gpmd->layername[0] = '\0';
+ ARRAY_SET_ITEMS(gpmd->rgb, 1.0f, 1.0f, 1.0f);
+ gpmd->flag |= GP_TINT_CREATE_COLORS;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* tint strokes */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ TintGpencilModifierData *mmd = (TintGpencilModifierData *)md;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 1, gpl, gps,
+ mmd->flag & GP_TINT_INVERT_LAYER, mmd->flag & GP_TINT_INVERT_PASS))
+ {
+ return;
+ }
+
+ interp_v3_v3v3(gps->runtime.tmp_stroke_rgba, gps->runtime.tmp_stroke_rgba, mmd->rgb, mmd->factor);
+ 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_stroke_rgba[3] += mmd->factor - 1.0f;
+ if (gps->runtime.tmp_fill_rgba[3] > 1e-5) {
+ gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f;
+ }
+ }
+
+ CLAMP4(gps->runtime.tmp_stroke_rgba, 0.0f, 1.0f);
+ CLAMP4(gps->runtime.tmp_fill_rgba, 0.0f, 1.0f);
+
+ /* 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);
+ }
+ }
+}
+
+static void bakeModifier(
+ Main *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 = give_current_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);
+
+ /* look for color */
+ if (mmd->flag & GP_TINT_CREATE_COLORS) {
+ Material *newmat = (Material *)BLI_ghash_lookup(gh_color, mat->id.name);
+ if (newmat == NULL) {
+ BKE_object_material_slot_add(bmain, ob);
+ newmat = BKE_material_copy(bmain, mat);
+ assign_material(bmain, ob, newmat, ob->totcol, BKE_MAT_ASSIGN_EXISTING);
+
+ 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);
+ }
+ /* reasign color index */
+ int idx = BKE_object_material_slot_find_index(ob, newmat);
+ gps->mat_nr = idx - 1;
+ }
+ else {
+ /* reuse existing color */
+ copy_v4_v4(gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba);
+ copy_v4_v4(gp_style->fill_rgba, gps->runtime.tmp_fill_rgba);
+ }
+
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+ /* free hash buffers */
+ if (gh_color) {
+ BLI_ghash_free(gh_color, NULL, NULL);
+ gh_color = NULL;
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Tint = {
+ /* name */ "Tint",
+ /* structName */ "TintGpencilModifierData",
+ /* structSize */ sizeof(TintGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 8273f3f1992..b9cc1de447f 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -260,6 +260,14 @@ data_to_c_simple(shaders/gpu_shader_vertex_world.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vsm_store_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vsm_store_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_gpencil_stroke_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_gpencil_stroke_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_gpencil_stroke_geom.glsl SRC)
+
+data_to_c_simple(shaders/gpu_shader_gpencil_fill_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_gpencil_fill_frag.glsl SRC)
+
+
if(WITH_MOD_SMOKE)
add_definitions(-DWITH_SMOKE)
endif()
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 7f334cec21f..704abdb13a1 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -346,7 +346,10 @@ typedef enum GPUBuiltinShader {
GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE, /* Uniformly scaled */
GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE,
GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR,
- /* specialized for UI drawing */
+ /* grease pencil drawing */
+ GPU_SHADER_GPENCIL_STROKE,
+ GPU_SHADER_GPENCIL_FILL,
+ /* specialized for widget drawing */
GPU_SHADER_2D_WIDGET_BASE,
GPU_SHADER_2D_WIDGET_BASE_INST,
GPU_SHADER_2D_WIDGET_SHADOW,
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 3543c73f71d..0d5183d82ab 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -162,6 +162,13 @@ extern char datatoc_gpu_shader_vsm_store_frag_glsl[];
extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[];
extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[];
+extern char datatoc_gpu_shader_gpencil_stroke_vert_glsl[];
+extern char datatoc_gpu_shader_gpencil_stroke_frag_glsl[];
+extern char datatoc_gpu_shader_gpencil_stroke_geom_glsl[];
+
+extern char datatoc_gpu_shader_gpencil_fill_vert_glsl[];
+extern char datatoc_gpu_shader_gpencil_fill_frag_glsl[];
+
/* cache of built-in shaders (each is created on first use) */
static GPUShader *builtin_shaders[GPU_NUM_BUILTIN_SHADERS] = { NULL };
@@ -868,6 +875,13 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
datatoc_gpu_shader_2D_nodelink_frag_glsl },
[GPU_SHADER_2D_NODELINK_INST] = { datatoc_gpu_shader_2D_nodelink_vert_glsl,
datatoc_gpu_shader_2D_nodelink_frag_glsl },
+
+ [GPU_SHADER_GPENCIL_STROKE] = { datatoc_gpu_shader_gpencil_stroke_vert_glsl,
+ datatoc_gpu_shader_gpencil_stroke_frag_glsl,
+ datatoc_gpu_shader_gpencil_stroke_geom_glsl },
+
+ [GPU_SHADER_GPENCIL_FILL] = { datatoc_gpu_shader_gpencil_fill_vert_glsl,
+ datatoc_gpu_shader_gpencil_fill_frag_glsl },
};
if (builtin_shaders[shader] == NULL) {
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl
new file mode 100644
index 00000000000..328fbbe26a1
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl
@@ -0,0 +1,166 @@
+uniform vec4 color;
+uniform vec4 color2;
+uniform int fill_type;
+uniform float mix_factor;
+
+uniform float g_angle;
+uniform float g_radius;
+uniform float g_boxsize;
+uniform vec2 g_scale;
+uniform vec2 g_shift;
+
+uniform float t_angle;
+uniform vec2 t_scale;
+uniform vec2 t_offset;
+uniform int t_mix;
+uniform int t_flip;
+uniform float t_opacity;
+
+uniform sampler2D myTexture;
+
+/* keep this list synchronized with list in DNA_brush_types.h */
+#define SOLID 0
+#define GRADIENT 1
+#define RADIAL 2
+#define CHESS 3
+#define TEXTURE 4
+
+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) {
+ if (flip == 0) {
+ ocolor = color;
+ }
+ else {
+ ocolor = tcolor;
+ }
+ }
+ else {
+ if (flip == 0) {
+ ocolor = color;
+ }
+ else {
+ ocolor = color2;
+ }
+ }
+ }
+ /* full color B */
+ else if (mixv == 0.0) {
+ if (tmix == 1) {
+ if (flip == 0) {
+ ocolor = tcolor;
+ }
+ else {
+ ocolor = color;
+ }
+ }
+ else {
+ if (flip == 0) {
+ ocolor = color2;
+ }
+ else {
+ ocolor = color;
+ }
+ }
+ }
+ /* mix of colors */
+ else {
+ if (tmix == 1) {
+ if (flip == 0) {
+ ocolor = mix(color, tcolor, factor);
+ }
+ else {
+ ocolor = mix(tcolor, color, factor);
+ }
+ }
+ else {
+ if (flip == 0) {
+ ocolor = mix(color, color2, factor);
+ }
+ else {
+ ocolor = mix(color2, color, factor);
+ }
+ }
+ }
+}
+
+void main()
+{
+ vec2 t_center = vec2(0.5, 0.5);
+ mat2 matrot_tex = mat2(cos(t_angle), -sin(t_angle), sin(t_angle), cos(t_angle));
+ vec2 rot_tex = (matrot_tex * (texCoord_interp - t_center)) + t_center + t_offset;
+ vec4 tmp_color = texture2D(myTexture, rot_tex * t_scale);
+ vec4 text_color = vec4(tmp_color[0], tmp_color[1], tmp_color[2], tmp_color[3] * t_opacity);
+ vec4 chesscolor;
+
+ /* solid fill */
+ if (fill_type == SOLID) {
+ if (t_mix == 1) {
+ fragColor = mix(color, text_color, mix_factor);
+ }
+ else {
+ fragColor = color;
+ }
+ }
+ else {
+ vec2 center = vec2(0.5, 0.5) + g_shift;
+ mat2 matrot = mat2(cos(g_angle), -sin(g_angle), sin(g_angle), cos(g_angle));
+ vec2 rot = (((matrot * (texCoord_interp - center)) + center) * g_scale) + g_shift;
+ /* gradient */
+ if (fill_type == GRADIENT) {
+ set_color(color, color2, text_color, mix_factor, rot.x - mix_factor + 0.5, t_mix, t_flip, fragColor);
+ }
+ /* radial gradient */
+ if (fill_type == RADIAL) {
+ float in_rad = g_radius * mix_factor;
+ float ex_rad = g_radius - in_rad;
+ float intensity = 0;
+ float distance = length((center - texCoord_interp) * g_scale);
+ if (distance > g_radius) {
+ discard;
+ }
+ if (distance > in_rad) {
+ intensity = clamp(((distance - in_rad) / ex_rad), 0.0, 1.0);
+ }
+ set_color(color, color2, text_color, mix_factor, intensity, t_mix, t_flip, fragColor);
+ }
+ /* chessboard */
+ if (fill_type == CHESS) {
+ vec2 pos = rot / g_boxsize;
+ if ((fract(pos.x) < 0.5 && fract(pos.y) < 0.5) || (fract(pos.x) > 0.5 && fract(pos.y) > 0.5)) {
+ if (t_flip == 0) {
+ chesscolor = color;
+ }
+ else {
+ chesscolor = color2;
+ }
+ }
+ else {
+ if (t_flip == 0) {
+ chesscolor = color2;
+ }
+ else {
+ chesscolor = color;
+ }
+ }
+ /* mix with texture */
+ if (t_mix == 1) {
+ fragColor = mix(chesscolor, text_color, mix_factor);
+ }
+ else {
+ fragColor = chesscolor;
+ }
+ }
+ /* texture */
+ if (fill_type == TEXTURE) {
+ fragColor = text_color;
+ }
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_fill_vert.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_vert.glsl
new file mode 100644
index 00000000000..2bc381a3689
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_vert.glsl
@@ -0,0 +1,11 @@
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in vec2 texCoord;
+out vec2 texCoord_interp;
+
+void main(void)
+{
+ gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 );
+ texCoord_interp = texCoord;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl
new file mode 100644
index 00000000000..7bb7693d202
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl
@@ -0,0 +1,20 @@
+in vec4 mColor;
+in vec2 mTexCoord;
+
+out vec4 fragColor;
+
+void main()
+{
+ const vec2 center = vec2(0, 0.5);
+ vec4 tColor = vec4(mColor);
+ /* if alpha < 0, then encap */
+ if (mColor.a < 0) {
+ tColor.a = tColor.a * -1.0;
+ float dist = length(mTexCoord - center);
+ if (dist > 0.25) {
+ discard;
+ }
+ }
+ /* Solid */
+ fragColor = tColor;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl
new file mode 100644
index 00000000000..3de1bd838b3
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl
@@ -0,0 +1,196 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 Viewport;
+uniform int xraymode;
+
+layout(lines_adjacency) in;
+layout(triangle_strip, max_vertices = 13) out;
+
+in vec4 finalColor[4];
+in float finalThickness[4];
+
+out vec4 mColor;
+out vec2 mTexCoord;
+
+#define GP_XRAY_FRONT 0
+#define GP_XRAY_3DSPACE 1
+#define GP_XRAY_BACK 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 0.0;
+ }
+ if (xraymode == GP_XRAY_3DSPACE) {
+ return (point.z / point.w);
+ }
+ if (xraymode == GP_XRAY_BACK) {
+ return 1.0;
+ }
+
+ /* in front by default */
+ return 0.0;
+}
+void main(void)
+{
+ float MiterLimit = 0.75;
+
+ /* 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;
+
+ /* 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 (alpha < 0 used as endcap flag)*/
+ if (P0 == P2) {
+ mTexCoord = vec2(1, 0.5);
+ mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ;
+ vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0;
+ gl_Position = vec4((sp1 + svn1) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0);
+ mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ;
+ gl_Position = vec4((sp1 - (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 1);
+ mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ;
+ gl_Position = vec4((sp1 + (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+ }
+
+ /* generate the triangle strip */
+ mTexCoord = vec2(0, 0);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 + length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 1);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 - length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0);
+ mColor = finalColor[2];
+ gl_Position = vec4((sp2 + length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 1);
+ mColor = finalColor[2];
+ gl_Position = vec4((sp2 - length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ /* generate the end endcap (alpha < 0 used as endcap flag)*/
+ if (P1 == P3) {
+ mTexCoord = vec2(0, 1);
+ mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ;
+ gl_Position = vec4((sp2 + (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0);
+ mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ;
+ gl_Position = vec4((sp2 - (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(1, 0.5);
+ mColor = vec4(finalColor[2].rgb, finalColor[2].a * -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/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl
new file mode 100644
index 00000000000..5f4f56dcca1
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl
@@ -0,0 +1,33 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ProjectionMatrix;
+
+uniform float pixsize; /* rv3d->pixsize */
+uniform float pixelsize; /* U.pixelsize */
+uniform int keep_size;
+uniform float objscale;
+uniform int pixfactor;
+
+in vec3 pos;
+in vec4 color;
+in float thickness;
+
+out vec4 finalColor;
+out float finalThickness;
+
+#define TRUE 1
+
+float defaultpixsize = pixsize * pixelsize * (1000.0 / pixfactor);
+
+void main(void)
+{
+ gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 );
+ 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);
+ }
+}
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index ec71f28cb23..634819b33ce 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -564,6 +564,7 @@ enum {
INDEX_ID_IP,
INDEX_ID_AC,
INDEX_ID_KE,
+ INDEX_ID_PAL,
INDEX_ID_GD,
INDEX_ID_NT,
INDEX_ID_IM,
@@ -581,7 +582,6 @@ enum {
INDEX_ID_TXT,
INDEX_ID_SO,
INDEX_ID_GR,
- INDEX_ID_PAL,
INDEX_ID_PC,
INDEX_ID_BR,
INDEX_ID_PA,
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index fc3b4afe18d..dcb7fbd344b 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -44,6 +44,7 @@
struct CurveMapping;
struct MTex;
struct Image;
+struct Material;
typedef struct BrushClone {
struct Image *image; /* image for clone tool */
@@ -51,6 +52,109 @@ typedef struct BrushClone {
float alpha, pad; /* transparency for drawing of clone image */
} BrushClone;
+
+typedef struct BrushGpencilSettings {
+ float draw_smoothfac; /* amount of smoothing to apply to newly created strokes */
+ float draw_sensitivity; /* amount of sensivity to apply to newly created strokes */
+ float draw_strength; /* amount of alpha strength to apply to newly created strokes */
+ float draw_jitter; /* amount of jitter to apply to newly created strokes */
+ float draw_angle; /* angle when the brush has full thickness */
+ float draw_angle_factor; /* factor to apply when angle change (only 90 degrees) */
+ float draw_random_press; /* factor of randomness for pressure */
+ float draw_random_strength; /* factor of strength for strength */
+ float draw_random_sub; /* factor of randomness for subdivision */
+ short draw_smoothlvl; /* number of times to apply smooth factor to new strokes */
+ short draw_subdivide; /* number of times to subdivide new strokes */
+ short flag; /* internal grease pencil drawing flags */
+
+ short thick_smoothlvl; /* number of times to apply thickness smooth factor to new strokes */
+ float thick_smoothfac; /* amount of thickness smoothing to apply to newly created strokes */
+
+ float fill_threshold; /* factor for transparency */
+ short fill_leak; /* number of pixel to consider the leak is too small (x 2) */
+ char pad_1[6];
+
+ int fill_simplylvl; /* number of simplify steps */
+ int fill_draw_mode; /* type of control lines drawing mode */
+ int icon_id; /* icon identifier */
+
+ int input_samples; /* maximum distance before generate new point for very fast mouse movements */
+ float uv_random; /* random factor for UV rotation */
+
+ int brush_type; /* type of brush (draw, fill, erase, etc..) */
+ int eraser_mode; /* soft, hard or stroke */
+ float active_smooth; /* smooth while drawing factor */
+ char pad_2[4];
+
+ struct CurveMapping *curve_sensitivity;
+ struct CurveMapping *curve_strength;
+ struct CurveMapping *curve_jitter;
+
+ /* optional link of material to replace default in context */
+ struct Material *material; /* material */
+} BrushGpencilSettings;
+
+/* BrushGpencilSettings->gp_flag */
+typedef enum eGPDbrush_Flag {
+ /* brush use pressure */
+ GP_BRUSH_USE_PRESSURE = (1 << 0),
+ /* brush use pressure for alpha factor */
+ 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 */
+ GP_BRUSH_FILL_SHOW_HELPLINES = (1 << 7),
+ /* lazy mouse */
+ GP_BRUSH_STABILIZE_MOUSE = (1 << 8),
+ /* lazy mouse override (internal only) */
+ GP_BRUSH_STABILIZE_MOUSE_TEMP = (1 << 9),
+ /* default eraser brush for quick switch */
+ GP_BRUSH_DEFAULT_ERASER = (1 << 10),
+ /* settings group */
+ GP_BRUSH_GROUP_SETTINGS = (1 << 11),
+ /* Random settings group */
+ GP_BRUSH_GROUP_RANDOM = (1 << 12)
+} eGPDbrush_Flag;
+
+/* BrushGpencilSettings->gp_fill_draw_mode */
+typedef enum eGP_FillDrawModes {
+ GP_FILL_DMODE_BOTH = 0,
+ GP_FILL_DMODE_STROKE = 1,
+ GP_FILL_DMODE_CONTROL = 2,
+} eGP_FillDrawModes;
+
+/* BrushGpencilSettings->brush type */
+typedef enum eGP_BrushType {
+ GP_BRUSH_TYPE_DRAW = 0,
+ GP_BRUSH_TYPE_FILL = 1,
+ GP_BRUSH_TYPE_ERASE = 2,
+} eGP_BrushType;
+
+/* BrushGpencilSettings->gp_eraser_mode */
+typedef enum eGP_BrushEraserMode {
+ GP_BRUSH_ERASER_SOFT = 0,
+ GP_BRUSH_ERASER_HARD = 1,
+ GP_BRUSH_ERASER_STROKE = 2,
+} eGP_BrushEraserMode;
+
+/* BrushGpencilSettings default brush icons */
+typedef enum eGP_BrushIcons {
+ GP_BRUSH_ICON_PENCIL = 1,
+ GP_BRUSH_ICON_PEN = 2,
+ GP_BRUSH_ICON_INK = 3,
+ GP_BRUSH_ICON_INKNOISE = 4,
+ GP_BRUSH_ICON_BLOCK = 5,
+ GP_BRUSH_ICON_MARKER = 6,
+ GP_BRUSH_ICON_FILL = 7,
+ GP_BRUSH_ICON_ERASE_SOFT = 8,
+ GP_BRUSH_ICON_ERASE_HARD = 9,
+ GP_BRUSH_ICON_ERASE_STROKE = 10
+} eGP_BrushIcons;
+
typedef struct Brush {
ID id;
@@ -139,8 +243,10 @@ typedef struct Brush {
float mask_stencil_pos[2];
float mask_stencil_dimension[2];
-} Brush;
+ struct BrushGpencilSettings *gpencil_settings;
+
+} Brush;
typedef struct PaletteColor {
struct PaletteColor *next, *prev;
/* two values, one to store rgb, other to store values for sculpt/weight */
@@ -355,5 +461,6 @@ enum {
};
#define MAX_BRUSH_PIXEL_RADIUS 500
+#define GP_MAX_BRUSH_PIXEL_RADIUS 1000
#endif /* __DNA_BRUSH_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h
index 8ed38b0b05d..4f860e16b88 100644
--- a/source/blender/makesdna/DNA_color_types.h
+++ b/source/blender/makesdna/DNA_color_types.h
@@ -99,6 +99,7 @@ typedef enum eCurveMappingPreset {
CURVE_PRESET_MID9 = 4,
CURVE_PRESET_ROUND = 5,
CURVE_PRESET_ROOT = 6,
+ CURVE_PRESET_GAUSS = 7,
} eCurveMappingPreset;
/* histogram->mode */
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
new file mode 100644
index 00000000000..150b4a2d9f1
--- /dev/null
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -0,0 +1,404 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file DNA_greasepencil_modifier_types.h
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_GREASEPENCIL_TYPES_H__
+#define __DNA_GREASEPENCIL_TYPES_H__
+
+#include "DNA_defs.h"
+#include "DNA_listBase.h"
+
+/* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE!
+ * (ONLY ADD NEW ITEMS AT THE END)
+ */
+
+struct RNG;
+
+typedef enum GpencilModifierType {
+ eGpencilModifierType_None = 0,
+ eGpencilModifierType_Noise = 1,
+ eGpencilModifierType_Subdiv = 2,
+ eGpencilModifierType_Thick = 3,
+ eGpencilModifierType_Tint = 4,
+ eGpencilModifierType_Instance = 5,
+ eGpencilModifierType_Build = 6,
+ eGpencilModifierType_Opacity = 7,
+ eGpencilModifierType_Color = 8,
+ eGpencilModifierType_Lattice = 9,
+ eGpencilModifierType_Simplify = 10,
+ eGpencilModifierType_Smooth = 11,
+ eGpencilModifierType_Hook = 12,
+ eGpencilModifierType_Offset = 13,
+ eGpencilModifierType_Mirror = 14,
+ NUM_GREASEPENCIL_MODIFIER_TYPES
+} GpencilModifierType;
+
+typedef enum GpencilModifierMode {
+ eGpencilModifierMode_Realtime = (1 << 0),
+ eGpencilModifierMode_Render = (1 << 1),
+ eGpencilModifierMode_Editmode = (1 << 2),
+ eGpencilModifierMode_Expanded = (1 << 3),
+} GpencilModifierMode;
+
+typedef enum {
+ /* This modifier has been inserted in local override, and hence can be fully edited. */
+ eGpencilModifierFlag_StaticOverride_Local = (1 << 0),
+} GpencilModifierFlag;
+
+typedef struct GpencilModifierData {
+ struct GpencilModifierData *next, *prev;
+
+ int type, mode;
+ int stackindex;
+ short flag;
+ short pad;
+ char name[64]; /* MAX_NAME */
+
+ char *error;
+} GpencilModifierData;
+
+typedef struct NoiseGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+ int flag; /* several flags */
+ float factor; /* factor of noise */
+ int step; /* how many frames before recalculate randoms */
+ int gp_frame; /* last gp frame used */
+ int scene_frame; /* last scene frame used */
+ float vrand1, vrand2; /* random values */
+ struct RNG *rng;
+} NoiseGpencilModifierData;
+
+typedef enum eNoiseGpencil_Flag {
+ GP_NOISE_USE_RANDOM = (1 << 0),
+ GP_NOISE_MOD_LOCATION = (1 << 1),
+ 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_INVERT_LAYER = (1 << 6),
+ GP_NOISE_INVERT_PASS = (1 << 7),
+ GP_NOISE_INVERT_VGROUP = (1 << 8),
+ GP_NOISE_MOD_UV = (1 << 9),
+} eNoiseGpencil_Flag;
+
+typedef struct SubdivGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ int level; /* factor of subdivision */
+ char pad[4];
+} SubdivGpencilModifierData;
+
+typedef enum eSubdivGpencil_Flag {
+ GP_SUBDIV_SIMPLE = (1 << 0),
+ GP_SUBDIV_INVERT_LAYER = (1 << 1),
+ GP_SUBDIV_INVERT_PASS = (1 << 2),
+} eSubdivGpencil_Flag;
+
+typedef struct ThickGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ int thickness; /* Thickness change */
+ char pad[4];
+ struct CurveMapping *curve_thickness;
+} ThickGpencilModifierData;
+
+typedef enum eThickGpencil_Flag {
+ GP_THICK_INVERT_LAYER = (1 << 0),
+ GP_THICK_INVERT_PASS = (1 << 1),
+ GP_THICK_INVERT_VGROUP = (1 << 2),
+ GP_THICK_CUSTOM_CURVE = (1 << 3),
+ GP_THICK_NORMALIZE = (1 << 4),
+} eThickGpencil_Flag;
+
+typedef struct TintGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ float rgb[3]; /* Tint color */
+ float factor; /* Mix factor */
+} TintGpencilModifierData;
+
+typedef enum eTintGpencil_Flag {
+ GP_TINT_CREATE_COLORS = (1 << 0),
+ GP_TINT_INVERT_LAYER = (1 << 1),
+ GP_TINT_INVERT_PASS = (1 << 2),
+} eTintGpencil_Flag;
+
+typedef struct ColorGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ float hsv[3]; /* hsv factors */
+ char pad[4];
+} ColorGpencilModifierData;
+
+typedef enum eColorGpencil_Flag {
+ GP_COLOR_CREATE_COLORS = (1 << 0),
+ GP_COLOR_INVERT_LAYER = (1 << 1),
+ GP_COLOR_INVERT_PASS = (1 << 2),
+} eColorGpencil_Flag;
+
+typedef struct OpacityGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ float factor; /* Main Opacity factor */
+ char pad[4];
+} OpacityGpencilModifierData;
+
+typedef enum eOpacityGpencil_Flag {
+ GP_OPACITY_INVERT_LAYER = (1 << 0),
+ GP_OPACITY_INVERT_PASS = (1 << 1),
+ GP_OPACITY_INVERT_VGROUP = (1 << 2),
+} eOpacityGpencil_Flag;
+
+typedef struct InstanceGpencilModifierData {
+ GpencilModifierData modifier;
+ int count[3]; /* number of elements in array */
+ int flag; /* several flags */
+ float offset[3]; /* Location increments */
+ float shift[3]; /* shift increment */
+ float rnd_size; /* random size factor */
+ float rnd_rot; /* random size factor */
+ float rot[3]; /* Rotation changes */
+ float scale[3]; /* Scale changes */
+ float rnd[20]; /* (first element is the index) random values */
+ int lock_axis; /* lock shift to one axis */
+
+ int pass_index; /* custom index for passes */
+ char layername[64]; /* layer name */
+} InstanceGpencilModifierData;
+
+typedef enum eInstanceGpencil_Flag {
+ GP_INSTANCE_RANDOM_SIZE = (1 << 0),
+ GP_INSTANCE_RANDOM_ROT = (1 << 1),
+ GP_INSTANCE_INVERT_LAYER = (1 << 2),
+ GP_INSTANCE_INVERT_PASS = (1 << 3),
+ GP_INSTANCE_MAKE_OBJECTS = (1 << 4),
+} eInstanceGpencil_Flag;
+
+typedef struct BuildGpencilModifierData {
+ GpencilModifierData modifier;
+
+ char layername[64]; /* if set, restrict modifier to operating on this layer */
+ int pass_index;
+
+ int pad;
+
+ float start_frame; /* If GP_BUILD_RESTRICT_TIME is set, the defines the frame range where GP frames are considered */
+ float end_frame;
+
+ float start_delay; /* For each pair of gp keys, number of frames before strokes start appearing */
+ float length; /* For each pair of gp keys, number of frames that build effect must be completed within */
+
+ short flag; /* (eGpencilBuild_Flag) Options for controlling modifier behaviour */
+
+ short mode; /* (eGpencilBuild_Mode) How are strokes ordered */
+ short transition; /* (eGpencilBuild_Transition) In what order do stroke points appear/disappear */
+
+ short time_alignment; /* (eGpencilBuild_TimeAlignment) For the "Concurrent" mode, when should "shorter" strips start/end */
+} BuildGpencilModifierData;
+
+typedef enum eBuildGpencil_Mode {
+ /* Strokes are shown one by one until all have appeared */
+ GP_BUILD_MODE_SEQUENTIAL = 0,
+ /* All strokes start at the same time */
+ GP_BUILD_MODE_CONCURRENT = 1,
+} eBuildGpencil_Mode;
+
+typedef enum eBuildGpencil_Transition {
+ /* Show in forward order */
+ GP_BUILD_TRANSITION_GROW = 0,
+ /* Hide in reverse order */
+ GP_BUILD_TRANSITION_SHRINK = 1,
+ /* Hide in forward order */
+ GP_BUILD_TRANSITION_FADE = 2,
+} eBuildGpencil_Transition;
+
+typedef enum eBuildGpencil_TimeAlignment {
+ /* All strokes start at same time */
+ GP_BUILD_TIMEALIGN_START = 0,
+ /* All strokes end at same time */
+ GP_BUILD_TIMEALIGN_END = 1,
+
+ /* TODO: Random Offsets, Stretch-to-Fill */
+} eBuildGpencil_TimeAlignment;
+
+typedef enum eBuildGpencil_Flag {
+ /* Restrict modifier to particular layer/passes? */
+ GP_BUILD_INVERT_LAYER = (1 << 0),
+ GP_BUILD_INVERT_PASS = (1 << 1),
+
+ /* Restrict modifier to only operating between the nominated frames */
+ GP_BUILD_RESTRICT_TIME = (1 << 2),
+} eBuildGpencil_Flag;
+
+typedef struct LatticeGpencilModifierData {
+ GpencilModifierData modifier;
+ struct Object *object;
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ float strength;
+ char pad[4];
+ void *cache_data; /* runtime only (LatticeDeformData) */
+} LatticeGpencilModifierData;
+
+typedef enum eLatticeGpencil_Flag {
+ GP_LATTICE_INVERT_LAYER = (1 << 0),
+ GP_LATTICE_INVERT_PASS = (1 << 1),
+ GP_LATTICE_INVERT_VGROUP = (1 << 2),
+} eLatticeGpencil_Flag;
+
+typedef struct MirrorGpencilModifierData {
+ GpencilModifierData modifier;
+ struct Object *object;
+ char layername[64]; /* layer name */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+} MirrorGpencilModifierData;
+
+typedef enum eMirrorGpencil_Flag {
+ GP_MIRROR_INVERT_LAYER = (1 << 0),
+ GP_MIRROR_INVERT_PASS = (1 << 1),
+ GP_MIRROR_CLIPPING = (1 << 2),
+ GP_MIRROR_AXIS_X = (1 << 3),
+ GP_MIRROR_AXIS_Y = (1 << 4),
+ GP_MIRROR_AXIS_Z = (1 << 5),
+} eMirrorGpencil_Flag;
+
+typedef struct HookGpencilModifierData {
+ GpencilModifierData modifier;
+
+ struct Object *object;
+ char subtarget[64]; /* optional name of bone target, MAX_ID_NAME-2 */
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+
+ int flag;
+ char falloff_type; /* use enums from WarpGpencilModifier (exact same functionality) */
+ char pad[3];
+ float parentinv[4][4]; /* matrix making current transform unmodified */
+ float cent[3]; /* visualization of hook */
+ float falloff; /* if not zero, falloff is distance where influence zero */
+ float force;
+ struct CurveMapping *curfalloff;
+} HookGpencilModifierData;
+
+typedef enum eHookGpencil_Flag {
+ GP_HOOK_INVERT_LAYER = (1 << 0),
+ GP_HOOK_INVERT_PASS = (1 << 1),
+ GP_HOOK_INVERT_VGROUP = (1 << 2),
+ GP_HOOK_UNIFORM_SPACE = (1 << 3),
+} eHookGpencil_Flag;
+
+typedef enum eHookGpencil_Falloff {
+ eGPHook_Falloff_None = 0,
+ eGPHook_Falloff_Curve = 1,
+ eGPHook_Falloff_Sharp = 2,
+ eGPHook_Falloff_Smooth = 3,
+ eGPHook_Falloff_Root = 4,
+ eGPHook_Falloff_Linear = 5,
+ eGPHook_Falloff_Const = 6,
+ eGPHook_Falloff_Sphere = 7,
+ eGPHook_Falloff_InvSquare = 8,
+} eHookGpencil_Falloff;
+
+typedef struct SimplifyGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ float factor; /* factor of simplify */
+ short mode; /* type of simplify */
+ short step; /* every n vertex to keep */
+} SimplifyGpencilModifierData;
+
+typedef enum eSimplifyGpencil_Flag {
+ GP_SIMPLIFY_INVERT_LAYER = (1 << 0),
+ GP_SIMPLIFY_INVERT_PASS = (1 << 1),
+} eSimplifyGpencil_Flag;
+
+typedef enum eSimplifyGpencil_Mode {
+ /* Keep only one vertex every n vertices */
+ GP_SIMPLIFY_FIXED = 0,
+ /* Use RDP algorithm */
+ GP_SIMPLIFY_ADAPTATIVE = 1,
+} eSimplifyGpencil_Mode;
+
+typedef struct OffsetGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ float loc[3];
+ float rot[3];
+ float scale[3];
+ char pad[4];
+} OffsetGpencilModifierData;
+
+typedef enum eOffsetGpencil_Flag {
+ GP_OFFSET_INVERT_LAYER = (1 << 0),
+ GP_OFFSET_INVERT_PASS = (1 << 1),
+ GP_OFFSET_INVERT_VGROUP = (1 << 2)
+} eOffsetGpencil_Flag;
+
+typedef struct SmoothGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+ int flag; /* several flags */
+ float factor; /* factor of noise */
+ int step; /* how many times apply smooth */
+} SmoothGpencilModifierData;
+
+typedef enum eSmoothGpencil_Flag {
+ GP_SMOOTH_MOD_LOCATION = (1 << 0),
+ GP_SMOOTH_MOD_STRENGTH = (1 << 1),
+ GP_SMOOTH_MOD_THICKNESS = (1 << 2),
+ GP_SMOOTH_INVERT_LAYER = (1 << 3),
+ GP_SMOOTH_INVERT_PASS = (1 << 4),
+ GP_SMOOTH_INVERT_VGROUP = (1 << 5),
+ GP_SMOOTH_MOD_UV = (1 << 6),
+} eSmoothGpencil_Flag;
+
+#define MOD_MESHSEQ_READ_ALL \
+ (MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)
+
+#endif /* __DNA_GREASEPENCIL_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index e2ee561de7f..8febfbc8ffc 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -36,6 +36,17 @@
struct AnimData;
struct CurveMapping;
+struct GHash;
+struct MDeformVert;
+
+/* TODO: add size as userprefs parameter */
+#define GP_OBGPENCIL_DEFAULT_SIZE 0.2f
+#define GP_DEFAULT_PIX_FACTOR 1.0f
+#define GP_DEFAULT_GRID_LINES 4
+#define GP_MAX_INPUT_SAMPLES 10
+
+/* ***************************************** */
+/* GP Stroke Points */
/* Grease-Pencil Annotations - 'Stroke Point'
* -> Coordinates may either be 2d or 3d depending on settings at the time
@@ -47,7 +58,10 @@ typedef struct bGPDspoint {
float pressure; /* pressure of input device (from 0 to 1) at this point */
float strength; /* color strength (used for alpha factor) */
float time; /* seconds since start of stroke */
- int flag; /* additional options (NOTE: can shrink this field down later if needed) */
+ int flag; /* additional options */
+
+ float uv_fac; /* factor of uv along the stroke */
+ float uv_rot; /* uv rotation for dot mode */
} bGPDspoint;
/* bGPDspoint->flag */
@@ -59,54 +73,24 @@ typedef enum eGPDspoint_Flag {
GP_SPOINT_TAG = (1 << 1),
} eGPSPoint_Flag;
+/* ***************************************** */
+/* GP Fill - Triangle Tesselation Data */
+
/* Grease-Pencil Annotations - 'Triangle'
- * A triangle contains the index of three vertices for filling the stroke
- * This is only used if high quality fill is enabled.
- * (not saved to blend file).
+ * -> A triangle contains the index of three vertices for filling the stroke
+ * This is only used if high quality fill is enabled
*/
typedef struct bGPDtriangle {
/* indices for tesselated triangle used for GP Fill */
unsigned int verts[3];
+ /* texture coordinates for verts */
+ float uv[3][2];
} bGPDtriangle;
-/* GP brush (used for new strokes) */
-typedef struct bGPDbrush {
- struct bGPDbrush *next, *prev;
+/* ***************************************** */
- char info[64]; /* Brush name. Must be unique. */
- short thickness; /* thickness to apply to strokes */
- short flag;
- float draw_smoothfac; /* amount of smoothing to apply to newly created strokes */
- short draw_smoothlvl; /* number of times to apply smooth factor to new strokes */
- short sublevel; /* number of times to subdivide new strokes */
-
- float draw_sensitivity; /* amount of sensivity to apply to newly created strokes */
- float draw_strength; /* amount of alpha strength to apply to newly created strokes */
- float draw_jitter; /* amount of jitter to apply to newly created strokes */
- float draw_angle; /* angle when the brush has full thickness */
- float draw_angle_factor; /* factor to apply when angle change (only 90 degrees) */
- float draw_random_press; /* factor of randomness for sensitivity and strength */
- float draw_random_sub; /* factor of randomness for subdivision */
- struct CurveMapping *cur_sensitivity;
- struct CurveMapping *cur_strength;
- struct CurveMapping *cur_jitter;
-} bGPDbrush;
-
-/* bGPDbrush->flag */
-typedef enum eGPDbrush_Flag {
- /* brush is active */
- GP_BRUSH_ACTIVE = (1 << 0),
- /* brush use pressure */
- GP_BRUSH_USE_PRESSURE = (1 << 1),
- /* brush use pressure for alpha factor */
- GP_BRUSH_USE_STENGTH_PRESSURE = (1 << 2),
- /* brush use pressure for alpha factor */
- GP_BRUSH_USE_JITTER_PRESSURE = (1 << 3),
- /* brush use random for pressure */
- GP_BRUSH_USE_RANDOM_PRESSURE = (1 << 4),
- /* brush use random for strength */
- GP_BRUSH_USE_RANDOM_STRENGTH = (1 << 5)
-} eGPDbrush_Flag;
+/* ***************************************** */
+/* GP Palettes (Deprecated - 2.78 - 2.79 only) */
/* color of palettes */
typedef struct bGPDpalettecolor {
@@ -129,9 +113,7 @@ typedef enum eGPDpalettecolor_Flag {
/* do onion skinning */
PC_COLOR_ONIONSKIN = (1 << 3),
/* "volumetric" strokes */
- PC_COLOR_VOLUMETRIC = (1 << 4),
- /* Use High quality fill */
- PC_COLOR_HQ_FILL = (1 << 5)
+ PC_COLOR_VOLUMETRIC = (1 << 4)
} eGPDpalettecolor_Flag;
/* palette of colors */
@@ -152,6 +134,21 @@ typedef enum eGPDpalette_Flag {
PL_PALETTE_ACTIVE = (1 << 0)
} eGPDpalette_Flag;
+/* ***************************************** */
+/* GP Strokes */
+
+/* Runtime temp data for bGPDstroke */
+typedef struct bGPDstroke_runtime {
+ /* runtime final colors (result of original colors and modifiers) */
+ float tmp_stroke_rgba[4];
+ 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];
+
+ float multi_frame_falloff; /* runtime falloff factor (only for transform) */
+} bGPDstroke_runtime;
+
/* Grease-Pencil Annotations - 'Stroke'
* -> A stroke represents a (simplified version) of the curve
* drawn by the user in one 'mousedown'->'mouseup' operation
@@ -168,14 +165,16 @@ typedef struct bGPDstroke {
short flag, pad[2]; /* various settings about this stroke */
double inittime; /* Init time of stroke */
- /* The pointer to color is only used during drawing, but not saved
- * colorname is the join with the palette, but when draw, the pointer is update if the value is NULL
- * to speed up the drawing
- */
- char colorname[128]; /* color name */
- bGPDpalettecolor *palcolor; /* current palette color */
- /* temporary layer name only used during copy/paste to put the stroke in the original layer */
- char tmp_layerinfo[128];
+
+ char colorname[128] DNA_DEPRECATED; /* color name */
+
+ int mat_nr; /* material index */
+ char pad_[4];
+
+ struct MDeformVert *dvert; /* vertex weight data */
+
+ bGPDstroke_runtime runtime;
+ char pad_1[4];
} bGPDstroke;
/* bGPDstroke->flag */
@@ -190,14 +189,22 @@ typedef enum eGPDstroke_Flag {
GP_STROKE_SELECT = (1 << 3),
/* Recalculate triangulation for high quality fill (when true, force a new recalc) */
GP_STROKE_RECALC_CACHES = (1 << 4),
- /* Recalculate the color pointer using the name as index (true force a new recalc) */
- GP_STROKE_RECALC_COLOR = (1 << 5),
/* 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),
/* only for use with stroke-buffer (while drawing eraser) */
GP_STROKE_ERASER = (1 << 15)
} eGPDstroke_Flag;
+/* ***************************************** */
+/* GP Frame */
+
+/* Runtime temp data for bGPDframe */
+typedef struct bGPDframe_runtime {
+ float viewmatrix[4][4]; /* parent matrix for drawing */
+} bGPDframe_runtime;
+
/* Grease-Pencil Annotations - 'Frame'
* -> Acts as storage for the 'image' formed by strokes
*/
@@ -210,6 +217,8 @@ typedef struct bGPDframe {
short flag; /* temp settings */
short key_type; /* keyframe type (eBezTriple_KeyframeType) */
+
+ bGPDframe_runtime runtime;
} bGPDframe;
/* bGPDframe->flag */
@@ -220,6 +229,16 @@ typedef enum eGPDframe_Flag {
GP_FRAME_SELECT = (1 << 1)
} eGPDframe_Flag;
+/* ***************************************** */
+/* GP Layer */
+
+/* Runtime temp data for bGPDlayer */
+typedef struct bGPDlayer_runtime {
+ struct GHash *derived_data; /* runtime data created by modifiers */
+ int icon_id; /* id for dynamic icon used to show annotation color preview for layer */
+ char pad[4];
+} bGPDlayer_runtime;
+
/* Grease-Pencil Annotations - 'Layer' */
typedef struct bGPDlayer {
struct bGPDlayer *next, *prev;
@@ -228,27 +247,27 @@ typedef struct bGPDlayer {
bGPDframe *actframe; /* active frame (should be the frame that is currently being displayed) */
short flag; /* settings for layer */
- short thickness; /* current thickness to apply to strokes */
-
- short gstep; /* Ghosts Before: max number of ghost frames to show between active frame and the one before it (0 = only the ghost itself) */
- short gstep_next; /* Ghosts After: max number of ghost frames to show after active frame and the following it (0 = only the ghost itself) */
+ short onion_flag; /* Per-layer onion-skinning flags (eGPDlayer_OnionFlag) */
- float gcolor_prev[3]; /* optional color for ghosts before the active frame */
- float gcolor_next[3]; /* optional color for ghosts after the active frame */
+ float color[4]; /* Color for strokes in layers. Used for annotations, and for ruler (which uses GPencil internally) */
+ float fill[4]; /* Fill color for strokes in layers. Not used anymore (was only for) */
- float color[4]; /* Color for strokes in layers (replaced by palettecolor). Only used for ruler (which uses GPencil internally) */
- float fill[4]; /* Fill color for strokes in layers. Not used and replaced by palettecolor fill */
+ char info[128]; /* name/reference info for this layer (i.e. "director's comments, 12/3")
+ * needs to be kept unique, as it's used as the layer identifier */
- char info[128]; /* optional reference info about this layer (i.e. "director's comments, 12/3")
- * this is used for the name of the layer too and kept unique. */
+ short thickness; /* thickness to apply to strokes (Annotations) */
+ char pad_1[2];
struct Object *parent; /* parent object */
float inverse[4][4]; /* inverse matrix (only used if parented) */
char parsubstr[64]; /* String describing subobject info, MAX_ID_NAME-2 */
- short partype, pad;
+ short partype;
+ short line_change; /* Thickness adjustment */
float tintcolor[4]; /* Color used to tint layer, alpha value is used as factor */
float opacity; /* Opacity of the layer */
+
+ bGPDlayer_runtime runtime;
} bGPDlayer;
/* bGPDlayer->flag */
@@ -261,51 +280,89 @@ typedef enum eGPDlayer_Flag {
GP_LAYER_ACTIVE = (1 << 2),
/* draw points of stroke for debugging purposes */
GP_LAYER_DRAWDEBUG = (1 << 3),
- /* do onion skinning */
- GP_LAYER_ONIONSKIN = (1 << 4),
/* for editing in Action Editor */
GP_LAYER_SELECT = (1 << 5),
/* current frame for layer can't be changed */
GP_LAYER_FRAMELOCK = (1 << 6),
/* don't render xray (which is default) */
GP_LAYER_NO_XRAY = (1 << 7),
- /* use custom color for ghosts before current frame */
- GP_LAYER_GHOST_PREVCOL = (1 << 8),
- /* use custom color for ghosts after current frame */
- GP_LAYER_GHOST_NEXTCOL = (1 << 9),
/* "volumetric" strokes */
GP_LAYER_VOLUMETRIC = (1 << 10),
- /* Use high quality fill (instead of buggy legacy OpenGL Fill) */
- GP_LAYER_HQ_FILL = (1 << 11),
/* Unlock color */
GP_LAYER_UNLOCK_COLOR = (1 << 12),
- /* always show onion skins (i.e. even during renders/animation playback) */
- GP_LAYER_GHOST_ALWAYS = (1 << 13),
} eGPDlayer_Flag;
+/* bGPDlayer->onion_flag */
+typedef enum eGPDlayer_OnionFlag {
+ /* do onion skinning */
+ GP_LAYER_ONIONSKIN = (1 << 0),
+} eGPDlayer_OnionFlag;
+
+/* ***************************************** */
+/* GP Datablock */
+
+/* Runtime temp data for bGPdata */
+typedef struct bGPdata_runtime {
+ /* Drawing Manager cache */
+ struct GHash *batch_cache_data;
+ void *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */
+
+ /* GP Object drawing */
+ float scolor[4]; /* buffer stroke color */
+ float sfill[4]; /* buffer fill color */
+ short mode; /* settings for color */
+ short bstroke_style; /* buffer style for drawing strokes (used to select shader type) */
+ short bfill_style; /* buffer style for filling areas (used to select shader type) */
+
+ /* Stroke Buffer data (only used during paint-session)
+ * - buffer must be initialized before use, but freed after
+ * whole paint operation is over
+ */
+ short sbuffer_size; /* number of elements currently in cache */
+ short sbuffer_sflag; /* flags for stroke that cache represents */
+ char pad_[6];
+} bGPdata_runtime;
+
/* Grease-Pencil Annotations - 'DataBlock' */
typedef struct bGPdata {
ID id; /* Grease Pencil data is a datablock */
struct AnimData *adt; /* animation data - for animating draw settings */
- /* saved Grease-Pencil data */
+ /* Grease-Pencil data */
ListBase layers; /* bGPDlayers */
int flag; /* settings for this datablock */
- /* not-saved stroke buffer data (only used during paint-session)
- * - buffer must be initialized before use, but freed after
- * whole paint operation is over
- */
- short sbuffer_size; /* number of elements currently in cache */
- short sbuffer_sflag; /* flags for stroke that cache represents */
- void *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */
- float scolor[4]; /* buffer color using palettes */
- float sfill[4]; /* buffer fill color */
- char pad[6]; /* padding for compiler alignment error */
- short sflag; /* settings for palette color */
-
- /* saved palettes */
- ListBase palettes;
+ short xray_mode; /* xray mode for strokes (eGP_DepthOrdering) */
+ char pad_1[2];
+
+ /* Palettes */
+ ListBase palettes DNA_DEPRECATED; /* list of bGPDpalette's - Deprecated (2.78 - 2.79 only) */
+
+ /* 3D Viewport/Appearance Settings */
+ float pixfactor; /* factor to define pixel size conversion */
+ float line_color[4]; /* color for edit line */
+
+ /* Onion skinning */
+ float onion_factor; /* onion alpha factor change */
+ int onion_mode; /* onion skinning range (eGP_OnionModes) */
+ int onion_flag; /* onion skinning flags (eGPD_OnionFlag) */
+ short gstep; /* Ghosts Before: max number of ghost frames to show between active frame and the one before it (0 = only the ghost itself) */
+ short gstep_next; /* Ghosts After: max number of ghost frames to show after active frame and the following it (0 = only the ghost itself) */
+
+ float gcolor_prev[3]; /* optional color for ghosts before the active frame */
+ float gcolor_next[3]; /* optional color for ghosts after the active frame */
+
+ char pad[4];
+ struct Material **mat; /* materials array */
+ short totcol; /* total materials */
+
+ /* stats */
+ short totlayer;
+ short totframe;
+ short totstroke;
+ short totpoint;
+ char pad_2[6];
+ bGPdata_runtime runtime;
} bGPdata;
/* bGPdata->flag */
@@ -314,8 +371,12 @@ typedef struct bGPdata {
* changes made during the porting process.
*/
typedef enum eGPdata_Flag {
- /* don't allow painting to occur at all */
- /* GP_DATA_LMBPLOCK = (1 << 0), */
+ /* datablock is used for "annotations"
+ * NOTE: This flag used to be used in 2.4x, but should hardly ever have been set.
+ * We can use this freely now, as all GP datablocks from pre-2.8 will get
+ * set on file load (as many old use cases are for "annotations" only)
+ */
+ GP_DATA_ANNOTATIONS = (1 << 0),
/* show debugging info in viewport (i.e. status print) */
GP_DATA_DISPINFO = (1 << 1),
@@ -339,10 +400,80 @@ typedef enum eGPdata_Flag {
/* Stroke Editing Mode - Toggle to enable alternative keymap for easier editing of stroke points */
GP_DATA_STROKE_EDITMODE = (1 << 8),
- /* Convenience/cache flag to make it easier to quickly toggle onion skinning on/off */
+ /* 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)
+ GP_DATA_SHOW_DIRECTION = (1 << 10),
+
+ /* Batch drawing cache need to be recalculated */
+ GP_DATA_CACHE_IS_DIRTY = (1 << 11),
+
+ /* Stroke Paint Mode - Toggle paint mode */
+ GP_DATA_STROKE_PAINTMODE = (1 << 12),
+ /* Stroke Editing Mode - Toggle sculpt mode */
+ GP_DATA_STROKE_SCULPTMODE = (1 << 13),
+ /* Stroke Editing Mode - Toggle weight paint mode */
+ GP_DATA_STROKE_WEIGHTMODE = (1 << 14),
+
+ /* keep stroke thickness unchanged when zoom change */
+ GP_DATA_STROKE_KEEPTHICKNESS = (1 << 15),
+
+ /* Allow edit several frames at the same time */
+ GP_DATA_STROKE_MULTIEDIT = (1 << 16),
} eGPdata_Flag;
+/* gpd->onion_flag */
+typedef enum eGPD_OnionFlag {
+ /* use custom color for ghosts before current frame */
+ GP_ONION_GHOST_PREVCOL = (1 << 0),
+ /* use custom color for ghosts after current frame */
+ GP_ONION_GHOST_NEXTCOL = (1 << 1),
+ /* always show onion skins (i.e. even during renders/animation playback) */
+ GP_ONION_GHOST_ALWAYS = (1 << 2),
+ /* use fade color in onion skin */
+ GP_ONION_FADE = (1 << 3),
+ /* Loop showing first frame after last frame */
+ GP_ONION_LOOP = (1 << 4),
+} eGPD_OnionFlag;
+
+/* gpd->onion_mode */
+typedef enum eGP_OnionModes {
+ GP_ONION_MODE_ABSOLUTE = 0,
+ GP_ONION_MODE_RELATIVE = 1,
+ GP_ONION_MODE_SELECTED = 2,
+} eGP_OnionModes;
+
+/* xray modes (Depth Ordering) */
+typedef enum eGP_DepthOrdering {
+ GP_XRAY_FRONT = 0,
+ GP_XRAY_3DSPACE = 1,
+ GP_XRAY_BACK = 2
+} eGP_DepthOrdering;
+
+/* ***************************************** */
+/* Mode Checking Macros */
+
+/* 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_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_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_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))
+#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)))
+
#endif /* __DNA_GPENCIL_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index eb469895fd7..50d9b890724 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -54,6 +54,59 @@ typedef struct TexPaintSlot {
int pad;
} TexPaintSlot;
+typedef struct MaterialGPencilStyle {
+ struct Image *sima; /* Texture image for strokes */
+ struct Image *ima; /* Texture image for filling */
+ float stroke_rgba[4]; /* color for paint and strokes (alpha included) */
+ float fill_rgba[4]; /* color that should be used for drawing "fills" for strokes (alpha included) */
+ float mix_rgba[4]; /* secondary color used for gradients and other stuff */
+ short flag; /* settings */
+ short index; /* custom index for passes */
+ short stroke_style; /* style for drawing strokes (used to select shader type) */
+ short fill_style; /* style for filling areas (used to select shader type) */
+ float mix_factor; /* factor used to define shader behavior (several uses) */
+ float gradient_angle; /* angle used for gradients orientation */
+ float gradient_radius; /* radius for radial gradients */
+ float pattern_gridsize; /* cheesboard size */
+ float gradient_scale[2]; /* uv coordinates scale */
+ float gradient_shift[2]; /* factor to shift filling in 2d space */
+ float texture_angle; /* angle used for texture orientation */
+ float texture_scale[2]; /* texture scale (separated of uv scale) */
+ float texture_offset[2]; /* factor to shift texture in 2d space */
+ float texture_opacity; /* texture opacity */
+ float texture_pixsize; /* pixel size for uv along the stroke */
+ int mode; /* drawing mode (line or dots) */
+
+ int gradient_type; /* type of gradient */
+ char pad[4];
+} MaterialGPencilStyle;
+
+/* MaterialGPencilStyle->flag */
+typedef enum eMaterialGPencilStyle_Flag {
+ /* Fill Texture is a pattern */
+ GP_STYLE_FILL_PATTERN = (1 << 0),
+ /* don't display color */
+ GP_STYLE_COLOR_HIDE = (1 << 1),
+ /* protected from further editing */
+ GP_STYLE_COLOR_LOCKED = (1 << 2),
+ /* do onion skinning */
+ GP_STYLE_COLOR_ONIONSKIN = (1 << 3),
+ /* clamp texture */
+ GP_STYLE_COLOR_TEX_CLAMP = (1 << 4),
+ /* mix texture */
+ GP_STYLE_COLOR_TEX_MIX = (1 << 5),
+ /* Flip fill colors */
+ GP_STYLE_COLOR_FLIP_FILL = (1 << 6),
+ /* Stroke Texture is a pattern */
+ GP_STYLE_STROKE_PATTERN = (1 << 7)
+} eMaterialGPencilStyle_Flag;
+
+typedef enum eMaterialGPencilStyle_Mode {
+ GP_STYLE_MODE_LINE = 0, /* line */
+ GP_STYLE_MODE_DOTS = 1, /* dots */
+ GP_STYLE_MODE_BOX = 2, /* rectangles */
+} eMaterialGPencilStyle_Mode;
+
typedef struct Material {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
@@ -107,6 +160,9 @@ typedef struct Material {
/* Runtime cache for GLSL materials. */
ListBase gpumaterial;
+
+ /* grease pencil color */
+ struct MaterialGPencilStyle *gp_style;
} Material;
/* **************** MATERIAL ********************* */
@@ -229,4 +285,24 @@ enum {
MA_BS_HASHED,
};
+/* Grease Pencil Stroke styles */
+enum {
+ GP_STYLE_STROKE_STYLE_SOLID = 0,
+ GP_STYLE_STROKE_STYLE_TEXTURE
+};
+
+/* Grease Pencil Fill styles */
+enum {
+ GP_STYLE_FILL_STYLE_SOLID = 0,
+ GP_STYLE_FILL_STYLE_GRADIENT,
+ GP_STYLE_FILL_STYLE_CHESSBOARD,
+ GP_STYLE_FILL_STYLE_TEXTURE
+};
+
+/* Grease Pencil Gradient Types */
+enum {
+ GP_STYLE_GRADIENT_LINEAR = 0,
+ GP_STYLE_GRADIENT_RADIAL
+};
+
#endif
diff --git a/source/blender/makesdna/DNA_object_enums.h b/source/blender/makesdna/DNA_object_enums.h
index 802ca6c7d0d..01228376174 100644
--- a/source/blender/makesdna/DNA_object_enums.h
+++ b/source/blender/makesdna/DNA_object_enums.h
@@ -37,7 +37,10 @@ typedef enum eObjectMode {
OB_MODE_TEXTURE_PAINT = 1 << 4,
OB_MODE_PARTICLE_EDIT = 1 << 5,
OB_MODE_POSE = 1 << 6,
- OB_MODE_GPENCIL = 1 << 7, /* NOTE: Just a dummy to make the UI nicer */
+ OB_MODE_GPENCIL_EDIT = 1 << 7,
+ OB_MODE_GPENCIL_PAINT = 1 << 8,
+ OB_MODE_GPENCIL_SCULPT = 1 << 9,
+ OB_MODE_GPENCIL_WEIGHT = 1 << 10,
} eObjectMode;
/* Any mode where the brush system is used. */
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index a8d50543e80..47fb2feb7f4 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -180,7 +180,9 @@ typedef struct Object {
ListBase effect DNA_DEPRECATED; // XXX deprecated... keep for readfile
ListBase defbase; /* list of bDeformGroup (vertex groups) names and flag only */
ListBase modifiers; /* list of ModifierData structures */
+ ListBase greasepencil_modifiers; /* list of GpencilModifierData structures */
ListBase fmaps; /* list of facemaps */
+ ListBase shader_fx; /* list of viewport effects. Actually only used by grease pencil */
int mode; /* Local object mode */
int restore_mode;
@@ -351,6 +353,9 @@ enum {
/* 23 and 24 are for life and sector (old file compat.) */
OB_ARMATURE = 25,
+/* Grease Pencil object used in 3D view but not used for annotation in 2D */
+ OB_GPENCIL = 26,
+
OB_TYPE_MAX,
};
@@ -361,9 +366,9 @@ enum {
/* check if the object type supports materials */
#define OB_TYPE_SUPPORT_MATERIAL(_type) \
- ((_type) >= OB_MESH && (_type) <= OB_MBALL)
+ (((_type) >= OB_MESH && (_type) <= OB_MBALL) || ((_type) == OB_GPENCIL))
#define OB_TYPE_SUPPORT_VGROUP(_type) \
- (ELEM(_type, OB_MESH, OB_LATTICE))
+ (ELEM(_type, OB_MESH, OB_LATTICE, OB_GPENCIL))
#define OB_TYPE_SUPPORT_EDITMODE(_type) \
(ELEM(_type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE))
#define OB_TYPE_SUPPORT_PARVERT(_type) \
@@ -375,10 +380,10 @@ enum {
/* is this ID type used as object data */
#define OB_DATA_SUPPORT_ID(_id_type) \
- (ELEM(_id_type, ID_ME, ID_CU, ID_MB, ID_LA, ID_SPK, ID_LP, ID_CA, ID_LT, ID_AR))
+ (ELEM(_id_type, ID_ME, ID_CU, ID_MB, ID_LA, ID_SPK, ID_LP, ID_CA, ID_LT, ID_GD, ID_AR))
#define OB_DATA_SUPPORT_ID_CASE \
- ID_ME: case ID_CU: case ID_MB: case ID_LA: case ID_SPK: case ID_LP: case ID_CA: case ID_LT: case ID_AR
+ ID_ME: case ID_CU: case ID_MB: case ID_LA: case ID_SPK: case ID_LP: case ID_CA: case ID_LT: case ID_GD: case ID_AR
/* partype: first 4 bits: type */
enum {
@@ -466,6 +471,12 @@ enum {
OB_EMPTY_IMAGE = 8,
};
+/* gpencil add types */
+enum {
+ GP_EMPTY = 0,
+ GP_MONKEY = 1
+};
+
/* boundtype */
enum {
OB_BOUND_BOX = 0,
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index a4235a07ed5..6629eeae3fa 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -66,7 +66,6 @@ struct AnimData;
struct Editing;
struct SceneStats;
struct bGPdata;
-struct bGPDbrush;
struct MovieClip;
struct ColorSpace;
struct SceneCollection;
@@ -686,7 +685,8 @@ typedef struct RenderData {
/* render simplify */
short simplify_subsurf;
short simplify_subsurf_render;
- short pad9, pad10;
+ short simplify_gpencil;
+ short pad10;
float simplify_particles;
float simplify_particles_render;
@@ -905,6 +905,11 @@ typedef struct UvSculpt {
Paint paint;
} UvSculpt;
+/* grease pencil drawing brushes */
+typedef struct GpPaint {
+ Paint paint;
+} GpPaint;
+
/* ------------------------------------------- */
/* Vertex Paint */
@@ -929,15 +934,18 @@ enum {
typedef enum eGP_EditBrush_Types {
GP_EDITBRUSH_TYPE_SMOOTH = 0,
GP_EDITBRUSH_TYPE_THICKNESS = 1,
- GP_EDITBRUSH_TYPE_GRAB = 2,
- GP_EDITBRUSH_TYPE_PUSH = 3,
- GP_EDITBRUSH_TYPE_TWIST = 4,
- GP_EDITBRUSH_TYPE_PINCH = 5,
- GP_EDITBRUSH_TYPE_RANDOMIZE = 6,
- GP_EDITBRUSH_TYPE_SUBDIVIDE = 7,
- GP_EDITBRUSH_TYPE_SIMPLIFY = 8,
- GP_EDITBRUSH_TYPE_CLONE = 9,
- GP_EDITBRUSH_TYPE_STRENGTH = 10,
+ GP_EDITBRUSH_TYPE_STRENGTH = 2,
+ GP_EDITBRUSH_TYPE_GRAB = 3,
+ GP_EDITBRUSH_TYPE_PUSH = 4,
+ GP_EDITBRUSH_TYPE_TWIST = 5,
+ GP_EDITBRUSH_TYPE_PINCH = 6,
+ GP_EDITBRUSH_TYPE_RANDOMIZE = 7,
+ GP_EDITBRUSH_TYPE_CLONE = 8,
+ GP_EDITBRUSH_TYPE_SUBDIVIDE = 9,
+ GP_EDITBRUSH_TYPE_SIMPLIFY = 10,
+ /* add any sculpt brush above this value */
+ GP_EDITBRUSH_TYPE_WEIGHT = 11,
+ /* add any weight paint brush below this value. Do no mix brushes */
/* !!! Update GP_EditBrush_Data brush[###]; below !!! */
TOT_GP_EDITBRUSH_TYPES
@@ -956,6 +964,8 @@ typedef struct GP_EditBrush_Data {
short size; /* radius of brush */
short flag; /* eGP_EditBrush_Flag */
float strength; /* strength of effect */
+ float curcolor_add[3]; /* cursor color for add */
+ float curcolor_sub[3]; /* cursor color for sub */
} GP_EditBrush_Data;
/* GP_EditBrush_Data.flag */
@@ -969,20 +979,31 @@ typedef enum eGP_EditBrush_Flag {
GP_EDITBRUSH_FLAG_USE_FALLOFF = (1 << 2),
/* smooth brush affects pressure values as well */
- GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE = (1 << 3)
+ GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE = (1 << 3),
+ /* enable screen cursor */
+ GP_EDITBRUSH_FLAG_ENABLE_CURSOR = (1 << 4),
+ /* temporary invert action */
+ GP_EDITBRUSH_FLAG_TMP_INVERT = (1 << 5),
} eGP_EditBrush_Flag;
/* GPencil Stroke Sculpting Settings */
typedef struct GP_BrushEdit_Settings {
- GP_EditBrush_Data brush[11]; /* TOT_GP_EDITBRUSH_TYPES */
+ GP_EditBrush_Data brush[12]; /* TOT_GP_EDITBRUSH_TYPES */
void *paintcursor; /* runtime */
- int brushtype; /* eGP_EditBrush_Types */
+ int brushtype; /* eGP_EditBrush_Types (sculpt) */
int flag; /* eGP_BrushEdit_SettingsFlag */
int lock_axis; /* eGP_Lockaxis_Types lock drawing to one axis */
- float alpha; /* alpha factor for selection color */
+ char pad1[4];
+
+ /* 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.
+ */
+ int weighttype; /* eGP_EditBrush_Types (weight paint) */
+ char pad[4];
+ struct CurveMapping *cur_falloff; /* multiframe edit falloff effect by frame */
} GP_BrushEdit_Settings;
/* GP_BrushEdit_Settings.flag */
@@ -995,6 +1016,12 @@ typedef enum eGP_BrushEdit_SettingsFlag {
GP_BRUSHEDIT_FLAG_APPLY_STRENGTH = (1 << 2),
/* apply brush to thickness */
GP_BRUSHEDIT_FLAG_APPLY_THICKNESS = (1 << 3),
+ /* apply brush to thickness */
+ GP_BRUSHEDIT_FLAG_WEIGHT_MODE = (1 << 4),
+ /* enable falloff for multiframe editing */
+ GP_BRUSHEDIT_FLAG_FRAME_FALLOFF = (1 << 5),
+ /* apply brush to uv data */
+ GP_BRUSHEDIT_FLAG_APPLY_UV = (1 << 6),
} eGP_BrushEdit_SettingsFlag;
@@ -1213,6 +1240,7 @@ typedef struct ToolSettings {
VPaint *wpaint; /* weight paint */
Sculpt *sculpt;
UvSculpt *uvsculpt; /* uv smooth */
+ GpPaint *gp_paint; /* gpencil paint */
/* Vertex group weight - used only for editmode, not weight
* paint */
@@ -1236,19 +1264,19 @@ typedef struct ToolSettings {
/* Auto-IK */
short autoik_chainlen; /* runtime only */
- /* SCE_MPR_LOC/SCAL */
- char gizmo_flag;
-
/* Grease Pencil */
char gpencil_flags; /* flags/options for how the tool works */
- char gpencil_src; /* for main 3D view Grease Pencil, where data comes from */
char gpencil_v3d_align; /* stroke placement settings: 3D View */
char gpencil_v2d_align; /* : General 2D Editor */
char gpencil_seq_align; /* : Sequencer Preview */
char gpencil_ima_align; /* : Image Editor */
- char _pad3[3];
+ /* Annotations */
+ char annotate_v3d_align; /* stroke placement settings - 3D View */
+
+ short annotate_thickness; /* default stroke thickness for annotation strokes */
+ char _pad3[2];
/* Grease Pencil Sculpt */
struct GP_BrushEdit_Settings gp_sculpt;
@@ -1256,10 +1284,7 @@ typedef struct ToolSettings {
/* Grease Pencil Interpolation Tool(s) */
struct GP_Interpolate_Settings gp_interpolate;
- /* Grease Pencil Drawing Brushes (bGPDbrush) */
- ListBase gp_brushes;
-
- /* Image Paint (8 byttse aligned please!) */
+ /* Image Paint (8 bytes aligned please!) */
struct ImagePaintSettings imapaint;
/* Particle Editing */
@@ -1281,7 +1306,9 @@ typedef struct ToolSettings {
/* Alt+RMB option */
char edge_mode;
char edge_mode_live_unwrap;
- char _pad1;
+
+ /* SCE_MPR_LOC/SCAL */
+ char gizmo_flag;
/* Transform */
char transform_pivot_point;
@@ -1503,7 +1530,7 @@ typedef struct Scene {
/* Units */
struct UnitSettings unit;
- /* Grease Pencil */
+ /* Grease Pencil - Annotations */
struct bGPdata *gpd;
/* Movie Tracking */
@@ -1515,6 +1542,7 @@ typedef struct Scene {
uint64_t customdata_mask; /* XXX. runtime flag for drawing, actually belongs in the window, only used by BKE_object_handle_update() */
uint64_t customdata_mask_modal; /* XXX. same as above but for temp operator use (gl renders) */
+
/* Color Management */
ColorManagedViewSettings view_settings;
ColorManagedDisplaySettings display_settings;
@@ -2020,19 +2048,27 @@ typedef enum eImagePaintMode {
/* ToolSettings.gpencil_flags */
typedef enum eGPencil_Flags {
- /* "Continuous Drawing" - The drawing operator enters a mode where multiple strokes can be drawn */
- GP_TOOL_FLAG_PAINTSESSIONS_ON = (1 << 0),
/* When creating new frames, the last frame gets used as the basis for the new one */
GP_TOOL_FLAG_RETAIN_LAST = (1 << 1),
/* Add the strokes below all strokes in the layer */
- GP_TOOL_FLAG_PAINT_ONBACK = (1 << 2)
+ GP_TOOL_FLAG_PAINT_ONBACK = (1 << 2),
+ /* Show compact list of colors */
+ GP_TOOL_FLAG_THUMBNAIL_LIST = (1 << 3),
} eGPencil_Flags;
-/* ToolSettings.gpencil_src */
-typedef enum eGPencil_Source_3D {
- GP_TOOL_SOURCE_SCENE = 0,
- GP_TOOL_SOURCE_OBJECT = 1
-} eGPencil_Source_3d;
+/* scene->r.simplify_gpencil */
+typedef enum eGPencil_SimplifyFlags {
+ /* Simplify */
+ SIMPLIFY_GPENCIL_ENABLE = (1 << 0),
+ /* Simplify on play */
+ SIMPLIFY_GPENCIL_ON_PLAY = (1 << 1),
+ /* Simplify fill on viewport */
+ 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)
+} eGPencil_SimplifyFlags;
/* ToolSettings.gpencil_*_align - Stroke Placement mode flags */
typedef enum eGPencil_Placement_Flags {
@@ -2048,6 +2084,7 @@ typedef enum eGPencil_Placement_Flags {
/* "Use Endpoints" */
GP_PROJECT_DEPTH_STROKE_ENDPOINTS = (1 << 4),
+ GP_PROJECT_CURSOR = (1 << 5),
} eGPencil_Placement_Flags;
/* ToolSettings.particle flag */
diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h
new file mode 100644
index 00000000000..15147cf2b6c
--- /dev/null
+++ b/source/blender/makesdna/DNA_shader_fx_types.h
@@ -0,0 +1,196 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file DNA_shader_fx_types.h
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_SHADERFX_TYPES_H__
+#define __DNA_SHADERFX_TYPES_H__
+
+#include "DNA_defs.h"
+#include "DNA_listBase.h"
+
+struct DRWShadingGroup;
+
+/* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE!
+ * (ONLY ADD NEW ITEMS AT THE END)
+ */
+
+typedef enum ShaderFxType {
+ eShaderFxType_None = 0,
+ eShaderFxType_Blur = 1,
+ eShaderFxType_Flip = 2,
+ eShaderFxType_Light = 3,
+ eShaderFxType_Pixel = 4,
+ eShaderFxType_Swirl = 5,
+ eShaderFxType_Wave = 6,
+ eShaderFxType_Rim = 7,
+ eShaderFxType_Colorize = 8,
+ NUM_SHADER_FX_TYPES
+} ShaderFxType;
+
+typedef enum ShaderFxMode {
+ eShaderFxMode_Realtime = (1 << 0),
+ eShaderFxMode_Render = (1 << 1),
+ eShaderFxMode_Editmode = (1 << 2),
+ eShaderFxMode_Expanded = (1 << 3),
+} ShaderFxMode;
+
+typedef enum {
+ /* This fx has been inserted in local override, and hence can be fully edited. */
+ eShaderFxFlag_StaticOverride_Local = (1 << 0),
+} ShaderFxFlag;
+
+typedef struct ShaderFxData {
+ struct ShaderFxData *next, *prev;
+
+ int type, mode;
+ int stackindex;
+ short flag;
+ short pad;
+ char name[64]; /* MAX_NAME */
+
+ char *error;
+} ShaderFxData;
+
+/* Runtime temp data */
+typedef struct ShaderFxData_runtime {
+ struct DRWShadingGroup *fx_sh;
+ struct DRWShadingGroup *fx_sh_b;
+ struct DRWShadingGroup *fx_sh_c;
+} ShaderFxData_runtime;
+
+typedef struct BlurShaderFxData {
+ ShaderFxData shaderfx;
+ int radius[2];
+ int flag; /* flags */
+ int samples; /* number of samples */
+ float coc; /* circle of confusion */
+ int blur[2]; /* not visible in rna */
+ char pad[4];
+ ShaderFxData_runtime runtime;
+} BlurShaderFxData;
+
+typedef enum eBlurShaderFx_Flag {
+ FX_BLUR_DOF_MODE = (1 << 0)
+} eBlurShaderFx_Flag;
+
+typedef struct ColorizeShaderFxData {
+ ShaderFxData shaderfx;
+ int mode;
+ float low_color[4];
+ float high_color[4];
+ float factor;
+ int flag; /* flags */
+ char pad[4];
+ ShaderFxData_runtime runtime;
+} ColorizeShaderFxData;
+
+typedef enum ColorizeShaderFxModes {
+ eShaderFxColorizeMode_GrayScale = 0,
+ eShaderFxColorizeMode_Sepia = 1,
+ eShaderFxColorizeMode_BiTone = 2,
+ eShaderFxColorizeMode_Custom = 3,
+ eShaderFxColorizeMode_Transparent = 4,
+} ColorizeShaderFxModes;
+
+typedef struct FlipShaderFxData {
+ ShaderFxData shaderfx;
+ int flag; /* flags */
+ int flipmode; /* internal, not visible in rna */
+ ShaderFxData_runtime runtime;
+} FlipShaderFxData;
+
+typedef enum eFlipShaderFx_Flag {
+ FX_FLIP_HORIZONTAL = (1 << 0),
+ FX_FLIP_VERTICAL = (1 << 1),
+} eFlipShaderFx_Flag;
+
+typedef struct LightShaderFxData {
+ ShaderFxData shaderfx;
+ struct Object *object;
+ int flag; /* flags */
+ float energy;
+ float ambient;
+ float loc[4]; /* internal, not visible in rna */
+ char pad[4];
+ ShaderFxData_runtime runtime;
+} LightShaderFxData;
+
+typedef struct PixelShaderFxData {
+ ShaderFxData shaderfx;
+ int size[3]; /* last element used for shader only */
+ int flag; /* flags */
+ float rgba[4];
+ ShaderFxData_runtime runtime;
+} PixelShaderFxData;
+
+typedef enum ePixelShaderFx_Flag {
+ FX_PIXEL_USE_LINES = (1 << 0),
+} ePixelShaderFx_Flag;
+
+typedef struct RimShaderFxData {
+ ShaderFxData shaderfx;
+ int offset[2];
+ int flag; /* flags */
+ float rim_rgb[3];
+ float mask_rgb[3];
+ int mode;
+ int blur[2];
+ int samples;
+ char pad[4];
+ ShaderFxData_runtime runtime;
+} RimShaderFxData;
+
+typedef enum RimShaderFxModes {
+ eShaderFxRimMode_Normal = 0,
+ eShaderFxRimMode_Overlay = 1,
+ eShaderFxRimMode_Add = 2,
+ eShaderFxRimMode_Subtract = 3,
+ eShaderFxRimMode_Multiply = 4,
+ eShaderFxRimMode_Divide = 5,
+} RimShaderFxModes;
+
+typedef struct SwirlShaderFxData {
+ ShaderFxData shaderfx;
+ struct Object *object;
+ int flag; /* flags */
+ int radius;
+ float angle;
+ int transparent; /* not visible in rna */
+ ShaderFxData_runtime runtime;
+} SwirlShaderFxData;
+
+typedef enum eSwirlShaderFx_Flag {
+ FX_SWIRL_MAKE_TRANSPARENT = (1 << 0),
+} eSwirlShaderFx_Flag;
+
+typedef struct WaveShaderFxData {
+ ShaderFxData shaderfx;
+ float amplitude;
+ float period;
+ float phase;
+ int orientation;
+ int flag; /* flags */
+ char pad[4];
+ ShaderFxData_runtime runtime;
+} WaveShaderFxData;
+#endif /* __DNA_SHADERFX_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index d6d043b03ae..5404f4160fd 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -198,6 +198,7 @@ typedef enum eSpaceButtons_Context {
BCONTEXT_VIEW_LAYER = 13,
BCONTEXT_TOOL = 14,
BCONTEXT_WORKSPACE = 15,
+ BCONTEXT_SHADERFX = 16,
/* always as last... */
BCONTEXT_TOT
@@ -1346,7 +1347,7 @@ typedef enum eSpaceClip_Flag {
SC_SHOW_GRID = (1 << 9),
SC_SHOW_STABLE = (1 << 10),
SC_MANUAL_CALIBRATION = (1 << 11),
- SC_SHOW_GPENCIL = (1 << 12),
+ SC_SHOW_ANNOTATION = (1 << 12),
SC_SHOW_FILTERS = (1 << 13),
SC_SHOW_GRAPH_FRAMES = (1 << 14),
SC_SHOW_GRAPH_TRACKS_MOTION = (1 << 15),
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index e7a540f9afc..cb2c69e2fa1 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -651,7 +651,9 @@ typedef struct UserDef {
struct WalkNavigation walk_navigation;
short opensubdiv_compute_type;
- char pad5[6];
+ short gpencil_multisamples; /* eMultiSample_Type, amount of samples for Grease Pencil */
+
+ char pad5[4];
} UserDef;
extern UserDef U; /* from blenkernel blender.c */
@@ -958,7 +960,7 @@ typedef enum eNdof_Flag {
#define NDOF_PIXELS_PER_SECOND 600.0f
-/* UserDef.ogl_multisamples */
+/* UserDef.ogl_multisamples and gpencil_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 bbbaf8bb957..27b07a317ed 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -190,6 +190,14 @@ typedef struct View3DOverlay {
float wireframe_threshold;
char _pad0[4];
+ /* grease pencil setttings */
+ float gpencil_grid_scale;
+ float gpencil_paper_opacity;
+ int gpencil_grid_lines;
+ int gpencil_grid_axis;
+ float gpencil_grid_opacity;
+ char _pad1[4];
+
} View3DOverlay;
/* 3D ViewPort Struct */
@@ -256,7 +264,8 @@ typedef struct View3D {
char multiview_eye; /* multiview current eye - for internal use */
- char pad3[4];
+ /* actually only used to define the opacity of the grease pencil vertex in edit mode */
+ float vertex_opacity;
/* note, 'fx_settings.dof' is currently _not_ allocated,
* instead set (temporarily) from camera */
@@ -340,7 +349,7 @@ typedef struct View3D {
/* View3d->flag2 (short) */
#define V3D_RENDER_OVERRIDE (1 << 2)
#define V3D_SOLID_TEX (1 << 3)
-#define V3D_SHOW_GPENCIL (1 << 4)
+#define V3D_SHOW_ANNOTATION (1 << 4)
#define V3D_LOCK_CAMERA (1 << 5)
#define V3D_RENDER_SHADOW (1 << 6) /* This is a runtime only flag that's used to tell draw_mesh_object() that we're doing a shadow pass instead of a regular draw */
#define V3D_SHOW_RECONSTRUCTION (1 << 7)
@@ -353,9 +362,13 @@ typedef struct View3D {
#define V3D_OCCLUDE_WIRE (1 << 14)
#define V3D_SHOW_MODE_SHADE_OVERRIDE (1 << 15) /* XXX: DNA deprecated */
-
/* View3d->flag3 (short) */
-#define V3D_SHOW_WORLD (1 << 0) /* LEGACY replaced by V3D_SHADING_BACKGROUND_WORLD */
+#define V3D_SHOW_WORLD (1 << 0) /* LEGACY replaced by V3D_SHADING_BACKGROUND_WORLD */
+#define V3D_GP_SHOW_PAPER (1 << 2) /* Activate paper to cover all viewport */
+#define V3D_GP_SHOW_GRID (1 << 3) /* Activate paper grid */
+#define V3D_GP_SHOW_EDIT_LINES (1 << 4)
+#define V3D_GP_SHOW_MULTIEDIT_LINES (1 << 5)
+#define V3D_GP_SHOW_ONION_SKIN (1 << 6) /* main switch at view level */
/* View3DShading->light */
enum {
@@ -482,4 +495,12 @@ enum {
#define RV3D_CAMZOOM_MIN_FACTOR 0.1657359312880714853f
#define RV3D_CAMZOOM_MAX_FACTOR 44.9852813742385702928f
+/* View3d.gpencil_grid_axis */
+enum {
+ V3D_GP_GRID_AXIS_LOCK = (1 << 0),
+ V3D_GP_GRID_AXIS_X = (1 << 1),
+ V3D_GP_GRID_AXIS_Y = (1 << 2),
+ V3D_GP_GRID_AXIS_Z = (1 << 3),
+};
+
#endif
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index a1bfac66115..7b27ec05865 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -113,6 +113,8 @@ static const char *includefiles[] = {
"DNA_particle_types.h",
"DNA_cloth_types.h",
"DNA_gpencil_types.h",
+ "DNA_gpencil_modifier_types.h",
+ "DNA_shader_fx_types.h",
"DNA_windowmanager_types.h",
"DNA_anim_types.h",
"DNA_boid_types.h",
@@ -1337,6 +1339,8 @@ int main(int argc, char **argv)
#include "DNA_particle_types.h"
#include "DNA_cloth_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_shader_fx_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_anim_types.h"
#include "DNA_boid_types.h"
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index cb5e2e61f9a..16194c9b419 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -269,9 +269,6 @@ extern StructRNA RNA_FreestyleSettings;
extern StructRNA RNA_Function;
extern StructRNA RNA_GPencilFrame;
extern StructRNA RNA_GPencilLayer;
-extern StructRNA RNA_GPencilPalette;
-extern StructRNA RNA_GPencilPaletteColor;
-extern StructRNA RNA_GPencilBrush;
extern StructRNA RNA_GPencilInterpolateSettings;
extern StructRNA RNA_GPencilStroke;
extern StructRNA RNA_GPencilStrokePoint;
@@ -600,6 +597,31 @@ extern StructRNA RNA_SunLight;
extern StructRNA RNA_SurfaceCurve;
extern StructRNA RNA_SurfaceDeformModifier;
extern StructRNA RNA_SurfaceModifier;
+extern StructRNA RNA_GpencilModifier;
+extern StructRNA RNA_BuildGpencilModifier;
+extern StructRNA RNA_NoiseGpencilModifier;
+extern StructRNA RNA_SubdivGpencilModifier;
+extern StructRNA RNA_SimplifyGpencilModifier;
+extern StructRNA RNA_ThickGpencilModifier;
+extern StructRNA RNA_TintGpencilModifier;
+extern StructRNA RNA_ColorGpencilModifier;
+extern StructRNA RNA_InstanceGpencilModifier;
+extern StructRNA RNA_DupliGpencilModifier;
+extern StructRNA RNA_OpacityGpencilModifier;
+extern StructRNA RNA_LatticeGpencilModifier;
+extern StructRNA RNA_MirrorGpencilModifier;
+extern StructRNA RNA_SmoothGpencilModifier;
+extern StructRNA RNA_HookGpencilModifier;
+extern StructRNA RNA_OffsetGpencilModifier;
+extern StructRNA RNA_ShaderFx;
+extern StructRNA RNA_ShaderFxBlur;
+extern StructRNA RNA_ShaderFxColorize;
+extern StructRNA RNA_ShaderFxFlip;
+extern StructRNA RNA_ShaderFxLight;
+extern StructRNA RNA_ShaderFxPixel;
+extern StructRNA RNA_ShaderFxRim;
+extern StructRNA RNA_ShaderFxSwirl;
+extern StructRNA RNA_ShaderFxWave;
extern StructRNA RNA_TexMapping;
extern StructRNA RNA_Text;
extern StructRNA RNA_TextBox;
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 043375a066a..4c0861757f4 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -44,6 +44,7 @@ extern const EnumPropertyItem rna_enum_id_type_items[];
extern const EnumPropertyItem rna_enum_object_mode_items[];
extern const EnumPropertyItem rna_enum_object_empty_drawtype_items[];
+extern const EnumPropertyItem rna_enum_object_gpencil_type_items[];
extern const EnumPropertyItem rna_enum_metaelem_type_items[];
extern const EnumPropertyItem rna_enum_proportional_falloff_items[];
@@ -65,6 +66,8 @@ extern const EnumPropertyItem rna_enum_object_modifier_type_items[];
extern const EnumPropertyItem rna_enum_constraint_type_items[];
extern const EnumPropertyItem rna_enum_boidrule_type_items[];
extern const EnumPropertyItem rna_enum_sequence_modifier_type_items[];
+extern const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[];
+extern const EnumPropertyItem rna_enum_object_shaderfx_type_items[];
extern const EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[];
extern const EnumPropertyItem rna_enum_modifier_triangulate_ngon_method_items[];
@@ -228,6 +231,7 @@ const EnumPropertyItem *rna_node_socket_type_itemf(
struct bContext;
struct PointerRNA;
struct PropertyRNA;
+
const EnumPropertyItem *rna_TransformOrientation_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
const EnumPropertyItem *rna_Sensor_type_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
const EnumPropertyItem *rna_Actuator_type_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index eb32a5fc6cb..ec240c222a1 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -49,6 +49,8 @@ set(DEFSRC
rna_fcurve.c
rna_fluidsim.c
rna_gpencil.c
+ rna_gpencil_modifier.c
+ rna_shader_fx.c
rna_group.c
rna_image.c
rna_key.c
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 393ebc15d3e..b0713987e16 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3416,6 +3416,8 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_mesh.c", "rna_mesh_api.c", RNA_def_mesh},
{"rna_meta.c", "rna_meta_api.c", RNA_def_meta},
{"rna_modifier.c", NULL, RNA_def_modifier},
+ {"rna_gpencil_modifier.c", NULL, RNA_def_greasepencil_modifier},
+ {"rna_shader_fx.c", NULL, RNA_def_shader_fx },
{"rna_nla.c", NULL, RNA_def_nla},
{"rna_nodetree.c", NULL, RNA_def_nodetree},
{"rna_object.c", "rna_object_api.c", RNA_def_object},
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 4f1e29b482d..0f3e74c567f 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -31,6 +31,8 @@
#include "DNA_texture_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_workspace_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_math.h"
@@ -122,6 +124,44 @@ const EnumPropertyItem rna_enum_brush_image_tool_items[] = {
{0, NULL, 0, NULL, NULL}
};
+#ifndef RNA_RUNTIME
+static EnumPropertyItem rna_enum_gpencil_brush_types_items[] = {
+ { GP_BRUSH_TYPE_DRAW, "DRAW", ICON_GREASEPENCIL_STROKE_PAINT, "Draw", "The brush is of type used for drawing strokes" },
+ { GP_BRUSH_TYPE_FILL, "FILL", ICON_COLOR, "Fill", "The brush is of type used for filling areas" },
+ { GP_BRUSH_TYPE_ERASE, "ERASE", ICON_PANEL_CLOSE, "Erase", "The brush is used for erasing strokes" },
+ { 0, NULL, 0, NULL, NULL }
+};
+
+static EnumPropertyItem rna_enum_gpencil_brush_eraser_modes_items[] = {
+ { GP_BRUSH_ERASER_SOFT, "SOFT", 0, "Soft", "Use soft eraser" },
+ { GP_BRUSH_ERASER_HARD, "HARD", 0, "Hard", "Use hard eraser" },
+ { GP_BRUSH_ERASER_STROKE, "STROKE", 0, "Stroke", "Use stroke eraser" },
+ { 0, NULL, 0, NULL, NULL }
+};
+
+static EnumPropertyItem rna_enum_gpencil_fill_draw_modes_items[] = {
+ { GP_FILL_DMODE_STROKE, "STROKE", 0, "Strokes", "Use visible strokes as fill boundary limits" },
+ { GP_FILL_DMODE_CONTROL, "CONTROL", 0, "Control", "Use internal control lines as fill boundary limits" },
+ { GP_FILL_DMODE_BOTH, "BOTH", 0, "Both", "Use visible strokes and control lines as fill boundary limits" },
+ { 0, NULL, 0, NULL, NULL }
+};
+
+static EnumPropertyItem rna_enum_gpencil_brush_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", "" },
+ { GP_BRUSH_ICON_INKNOISE, "INKNOISE", ICON_GPBRUSH_INKNOISE, "Ink Noise", "" },
+ { GP_BRUSH_ICON_BLOCK, "BLOCK", ICON_GPBRUSH_BLOCK, "Block", "" },
+ { GP_BRUSH_ICON_MARKER, "MARKER", ICON_GPBRUSH_MARKER, "Marker", "" },
+ { GP_BRUSH_ICON_FILL, "FILL", ICON_GPBRUSH_FILL, "Fill", "" },
+ { GP_BRUSH_ICON_ERASE_SOFT, "SOFT", ICON_GPBRUSH_ERASE_SOFT, "Eraser Soft", "" },
+ { GP_BRUSH_ICON_ERASE_HARD, "HARD", ICON_GPBRUSH_ERASE_HARD, "Eraser Hard", "" },
+ { GP_BRUSH_ICON_ERASE_STROKE, "STROKE", ICON_GPBRUSH_ERASE_STROKE, "Eraser Stroke", "" },
+ { 0, NULL, 0, NULL, NULL }
+};
+#endif
+
+
#ifdef RNA_RUNTIME
#include "MEM_guardedalloc.h"
@@ -442,6 +482,33 @@ static void rna_Brush_icon_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
WM_main_add_notifier(NC_BRUSH | NA_EDITED, br);
}
+static const EnumPropertyItem *rna_DynamicGpencil_type_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ Main *bmain = CTX_data_main(C);
+ EnumPropertyItem *item = NULL, item_tmp = { 0 };
+ int totitem = 0;
+ int i = 0;
+
+ Brush *brush;
+ for (brush = bmain->brush.first; brush; brush = brush->id.next, i++) {
+ if (brush->gpencil_settings == NULL)
+ continue;
+
+ item_tmp.identifier = brush->id.name + 2;
+ item_tmp.name = brush->id.name + 2;
+ item_tmp.value = i;
+ item_tmp.icon = brush->gpencil_settings->icon_id;
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
static void rna_TextureSlot_brush_angle_update(bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
@@ -615,6 +682,58 @@ static const EnumPropertyItem *rna_Brush_stroke_itemf(bContext *C, PointerRNA *U
return brush_stroke_method_items;
}
}
+
+/* Grease Pencil Drawing Brushes Settings */
+static void rna_BrushGpencilSettings_default_eraser_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
+{
+ ToolSettings *ts = scene->toolsettings;
+ Paint *paint = &ts->gp_paint->paint;
+ Brush *brush_cur = paint->brush;
+
+ /* disable default eraser in all brushes */
+ for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+ if ((brush != brush_cur) &&
+ (brush->ob_mode == OB_MODE_GPENCIL_PAINT) &&
+ (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE))
+ {
+ brush->gpencil_settings->flag &= ~GP_BRUSH_DEFAULT_ERASER;
+ }
+ }
+}
+
+static void rna_BrushGpencilSettings_eraser_mode_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+{
+ ToolSettings *ts = scene->toolsettings;
+ Paint *paint = &ts->gp_paint->paint;
+ Brush *brush = paint->brush;
+
+ /* set eraser icon */
+ if ((brush) && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) {
+ switch (brush->gpencil_settings->eraser_mode) {
+ case GP_BRUSH_ERASER_SOFT:
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
+ break;
+ case GP_BRUSH_ERASER_HARD:
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
+ break;
+ case GP_BRUSH_ERASER_STROKE:
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE;
+ break;
+ default:
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
+ break;
+ }
+ }
+}
+
+static bool rna_BrushGpencilSettings_material_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
+{
+ Material *ma = (Material *)value.data;
+
+ /* GP materials only */
+ return (ma->gp_style != NULL);
+}
+
#else
static void rna_def_brush_texture_slot(BlenderRNA *brna)
@@ -809,6 +928,316 @@ static void rna_def_image_paint_capabilities(BlenderRNA *brna)
#undef IMAPAINT_TOOL_CAPABILITY
}
+static void rna_def_gpencil_options(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ /* Grease Pencil Drawing - generated dynamically */
+ static const EnumPropertyItem prop_dynamic_gpencil_type[] = {
+ { 1, "DRAW", 0, "Draw", "" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+ srna = RNA_def_struct(brna, "BrushGpencilSettings", NULL);
+ RNA_def_struct_sdna(srna, "BrushGpencilSettings");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Brush Settings", "Settings for grease pencil brush");
+
+ /* grease pencil drawing brushes */
+ prop = RNA_def_property(srna, "grease_pencil_tool", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "brush_type");
+ RNA_def_property_enum_items(prop, prop_dynamic_gpencil_type);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DynamicGpencil_type_itemf");
+ RNA_def_property_ui_text(prop, "Grease Pencil Tool", "");
+ /* TODO: GPXX review update */
+ RNA_def_property_update(prop, 0, NULL);
+ //RNA_def_property_update(prop, 0, "rna_Brush_gpencil_tool_update");
+
+ /* 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_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ 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_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_strength");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Strength", "Color strength for new strokes (affect alpha factor of color)");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Jitter factor for new strokes */
+ prop = RNA_def_property(srna, "pen_jitter", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_jitter");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Jitter", "Jitter factor for new strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Randomnes factor for pressure */
+ prop = RNA_def_property(srna, "random_pressure", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_random_press");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Pressure Randomness", "Randomness factor for pressure in new strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Randomnes factor for strength */
+ prop = RNA_def_property(srna, "random_strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_random_strength");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Strength Randomness", "Randomness factor strength in new strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Randomnes factor for subdivision */
+ prop = RNA_def_property(srna, "random_subdiv", PROP_FLOAT, PROP_NONE);
+ 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_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ 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");
+ RNA_def_property_range(prop, -M_PI_2, M_PI_2);
+ RNA_def_property_ui_text(prop, "Angle",
+ "Direction of the stroke at which brush gives maximal thickness "
+ "(0° for horizontal)");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Factor to change brush size depending of angle */
+ prop = RNA_def_property(srna, "angle_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_angle_factor");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Angle Factor",
+ "Reduce brush thickness by this factor when stroke is perpendicular to 'Angle' direction");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Smoothing factor for new strokes */
+ prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac");
+ RNA_def_property_range(prop, 0.0, 2.0f);
+ RNA_def_property_ui_text(prop, "Smooth",
+ "Amount of smoothing to apply after finish newly created strokes, to reduce jitter/noise");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Iterations of the Smoothing factor */
+ prop = RNA_def_property(srna, "pen_smooth_steps", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl");
+ RNA_def_property_range(prop, 1, 3);
+ RNA_def_property_ui_text(prop, "Iterations",
+ "Number of times to smooth newly created strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ 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_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ 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_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ 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");
+ RNA_def_property_range(prop, 0, 3);
+ RNA_def_property_ui_text(prop, "Subdivision Steps",
+ "Number of times to subdivide newly created strokes, for less jagged strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Curves for pressure */
+ prop = RNA_def_property(srna, "curve_sensitivity", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_sensitivity");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Curve Sensitivity", "Curve used for the sensitivity");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "curve_strength", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_strength");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Curve Strength", "Curve used for the strength");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "curve_jitter", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_jitter");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Curve Jitter", "Curve used for the jitter effect");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* fill threshold for transparence */
+ prop = RNA_def_property(srna, "gpencil_fill_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "fill_threshold");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Threshold",
+ "Threshold to consider color transparent for filling");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* fill leak size */
+ prop = RNA_def_property(srna, "gpencil_fill_leak", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "fill_leak");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Leak Size",
+ "Size in pixels to consider the leak closed");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* fill simplify steps */
+ prop = RNA_def_property(srna, "gpencil_fill_simplyfy_level", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "fill_simplylvl");
+ RNA_def_property_range(prop, 0, 10);
+ RNA_def_property_ui_text(prop, "Simplify",
+ "Number of simplify steps (large values reduce fill accuracy)");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "uv_random", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_random");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_text(prop, "UV Random", "Random factor for autogenerated UV rotation");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "input_samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "input_samples");
+ RNA_def_property_range(prop, 0, GP_MAX_INPUT_SAMPLES);
+ RNA_def_property_ui_text(prop, "Input Samples", "Generate intermediate points for very fast mouse movements. Set to 0 to disable");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* active smooth factor while drawing */
+ prop = RNA_def_property(srna, "active_smooth_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "active_smooth");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Active Smooth",
+ "Amount of smoothing while drawing ");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* brush standard icon */
+ prop = RNA_def_property(srna, "gp_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_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_ui_text(prop, "Grease Pencil Icon", "");
+
+ /* Flags */
+ prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_PRESSURE);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure", "Use tablet pressure");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_strength_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_STENGTH_PRESSURE);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure Strength", "Use tablet pressure for color strength");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_jitter_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_JITTER_PRESSURE);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure Jitter", "Use tablet pressure for jitter");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_stabilizer", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_STABILIZE_MOUSE);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Stabilizer",
+ "Draw lines with a delay to allow smooth strokes. Press Shift key to override while drawing");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ 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_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "gpencil_brush_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "brush_type");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_types_items);
+ RNA_def_property_ui_text(prop, "Type", "Category of the brush");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ 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);
+ RNA_def_property_ui_text(prop, "Mode", "Eraser Mode");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_BrushGpencilSettings_eraser_mode_update");
+
+ prop = RNA_def_property(srna, "gpencil_fill_draw_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "fill_draw_mode");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_fill_draw_modes_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode to draw boundary limits");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ /* Material */
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Material");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_BrushGpencilSettings_material_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_ui_text(prop, "Material", "Material used for strokes drawn using this brush");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "gpencil_fill_show_boundary", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_FILL_SHOW_HELPLINES);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Show Lines", "Show help lines for filling to see boundaries");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "gpencil_fill_hide", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_FILL_HIDE);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Hide", "Hide transparent lines to use as boundary for filling");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "default_eraser", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_DEFAULT_ERASER);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1);
+ RNA_def_property_ui_text(prop, "Default Eraser", "Use this brush when enable eraser with fast switch key");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_BrushGpencilSettings_default_eraser_update");
+
+ prop = RNA_def_property(srna, "enable_settings", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_GROUP_SETTINGS);
+ RNA_def_property_ui_text(prop, "Settings", "Enable additional post processing options for new strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "enable_random", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_GROUP_RANDOM);
+ RNA_def_property_ui_text(prop, "Random Settings", "Enable random settings for brush");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+}
+
static void rna_def_brush(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1373,6 +1802,10 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_TEXTURE_PAINT);
RNA_def_property_ui_text(prop, "Use Texture", "Use this brush in texture paint mode");
+ prop = RNA_def_property(srna, "use_paint_grease_pencil", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_GPENCIL_PAINT);
+ RNA_def_property_ui_text(prop, "Use Sculpt", "Use this brush in grease pencil drawing mode");
+
/* texture */
prop = RNA_def_property(srna, "texture_slot", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "BrushTextureSlot");
@@ -1475,6 +1908,13 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ImapaintToolCapabilities");
RNA_def_property_pointer_funcs(prop, "rna_Imapaint_tool_capabilities_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Image Painting Capabilities", "Brush's capabilities in image paint mode");
+
+ prop = RNA_def_property(srna, "gpencil_settings", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "BrushGpencilSettings");
+ RNA_def_property_pointer_sdna(prop, NULL, "gpencil_settings");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Gpencil Settings", "");
+
}
@@ -1543,6 +1983,7 @@ void RNA_def_brush(BlenderRNA *brna)
rna_def_brush_capabilities(brna);
rna_def_sculpt_capabilities(brna);
rna_def_image_paint_capabilities(brna);
+ rna_def_gpencil_options(brna);
rna_def_brush_texture_slot(brna);
rna_def_operator_stroke_element(brna);
}
diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c
index 7b07faf8ee7..781be07f1dc 100644
--- a/source/blender/makesrna/intern/rna_context.c
+++ b/source/blender/makesrna/intern/rna_context.c
@@ -52,6 +52,10 @@ const EnumPropertyItem rna_enum_context_mode_items[] = {
{CTX_MODE_PAINT_TEXTURE, "PAINT_TEXTURE", 0, "Texture Paint", ""},
{CTX_MODE_PARTICLE, "PARTICLE", 0, "Particle", ""},
{CTX_MODE_OBJECT, "OBJECT", 0, "Object", ""},
+ {CTX_MODE_GPENCIL_PAINT, "GPENCIL_PAINT", 0, "Grease Pencil Paint", "" },
+ {CTX_MODE_GPENCIL_EDIT, "GPENCIL_EDIT", 0, "Grease Pencil Edit", "" },
+ {CTX_MODE_GPENCIL_SCULPT, "GPENCIL_SCULPT", 0, "Grease Pencil Sculpt", "" },
+ {CTX_MODE_GPENCIL_WEIGHT, "GPENCIL_WEIGHT", 0, "Grease Pencil Weight 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 d9dba4679e0..f84f31b02f1 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -26,8 +26,12 @@
#include <stdlib.h>
+#include "BLI_math.h"
+
+#include "DNA_meshdata_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
+#include "DNA_brush_types.h"
#include "MEM_guardedalloc.h"
@@ -38,10 +42,12 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "rna_internal.h"
#include "WM_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "ED_gpencil.h"
@@ -53,31 +59,54 @@ static const EnumPropertyItem parent_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+#ifndef RNA_RUNTIME
+static EnumPropertyItem rna_enum_gpencil_xraymodes_items[] = {
+ { GP_XRAY_FRONT, "FRONT", 0, "Front", "Draw all strokes in front" },
+ { GP_XRAY_3DSPACE, "3DSPACE", 0, "3DSpace", "Draw strokes relative to other objects in 3D space" },
+ { GP_XRAY_BACK, "BACK", 0, "Back", "Draw all strokes on back" },
+ { 0, NULL, 0, NULL, NULL }
+};
+
+static EnumPropertyItem rna_enum_gpencil_onion_modes_items[] = {
+ { GP_ONION_MODE_ABSOLUTE, "ABSOLUTE", 0, "Frames", "Frames in absolute range of scene frame number" },
+ { GP_ONION_MODE_RELATIVE, "RELATIVE", 0, "Keyframes", "Frames in relative range of grease pencil keyframes" },
+ { GP_ONION_MODE_SELECTED, "SELECTED", 0, "Selected", "Only Selected Frames" },
+ { 0, NULL, 0, NULL, NULL }
+};
+#endif
#ifdef RNA_RUNTIME
#include "BLI_math.h"
+#include "BLI_ghash.h"
#include "WM_api.h"
+#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_gpencil.h"
-#include "BKE_action.h"
+#include "BKE_icons.h"
+#include "DEG_depsgraph.h"
-static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+
+static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
-static void rna_GPencil_editmode_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_GPencil_editmode_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
+ bGPdata *gpd = (bGPdata *)ptr->id.data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
/* Notify all places where GPencil data lives that the editing state is different */
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
WM_main_add_notifier(NC_SCENE | ND_MODE | NC_MOVIECLIP, NULL);
}
-static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void UNUSED_FUNCTION(rna_GPencil_onion_skinning_update)(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bGPdata *gpd = (bGPdata *)ptr->id.data;
bGPDlayer *gpl;
@@ -87,7 +116,7 @@ static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, Pointer
* stays in sync with the status of the actual layers
*/
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->flag & GP_LAYER_ONIONSKIN) {
+ if (gpl->onion_flag & GP_LAYER_ONIONSKIN) {
enabled = true;
}
}
@@ -102,16 +131,22 @@ static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, Pointer
rna_GPencil_update(bmain, scene, ptr);
}
-static void rna_GPencil_stroke_colorname_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+
+/* Poll Callback to filter GP Datablocks to only show those for Annotations */
+bool rna_GPencil_datablocks_annotations_poll(PointerRNA *UNUSED(ptr), const PointerRNA value)
{
- bGPDstroke *gps = (bGPDstroke *)ptr->data;
- gps->flag |= GP_STROKE_RECALC_COLOR;
- gps->palcolor = NULL;
+ bGPdata *gpd = value.data;
+ return (gpd->flag & GP_DATA_ANNOTATIONS) != 0;
+}
- /* Now do standard updates... */
- rna_GPencil_update(bmain, scene, ptr);
+/* Poll Callback to filter GP Datablocks to only show those for GP Objects */
+bool rna_GPencil_datablocks_obdata_poll(PointerRNA *UNUSED(ptr), const PointerRNA value)
+{
+ bGPdata *gpd = value.data;
+ return (gpd->flag & GP_DATA_ANNOTATIONS) == 0;
}
+
static char *rna_GPencilLayer_path(PointerRNA *ptr)
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
@@ -133,36 +168,6 @@ static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr, const char **
return PROP_EDITABLE;
}
-static void rna_GPencilLayer_line_width_range(PointerRNA *ptr, int *min, int *max,
- int *softmin, int *softmax)
-{
- bGPDlayer *gpl = ptr->data;
-
- /* The restrictions on max width here are due to OpenGL on Windows not supporting
- * any widths greater than 10 (for driver-drawn) strokes/points.
- *
- * Although most of our 2D strokes also don't suffer from this restriction,
- * it's relatively hard to test for that. So, for now, only volumetric strokes
- * get to be larger...
- */
-
- /* From GP v2 this value is used to increase or decrease the thickness of the stroke */
- if (gpl->flag & GP_LAYER_VOLUMETRIC) {
- *min = -300;
- *max = 300;
-
- *softmin = -100;
- *softmax = 100;
- }
- else {
- *min = -10;
- *max = 10;
-
- *softmin = -10;
- *softmax = 10;
- }
-}
-
/* set parent */
static void set_parent(bGPDlayer *gpl, Object *par, const int type, const char *substr)
{
@@ -202,21 +207,6 @@ static void rna_GPencilLayer_parent_set(PointerRNA *ptr, PointerRNA value)
set_parent(gpl, par, gpl->partype, gpl->parsubstr);
}
else {
- /* keep strokes in the same place, so apply current transformation */
- if (gpl->parent != NULL) {
- bGPDspoint *pt;
- int i;
- float diff_mat[4][4];
- /* calculate difference matrix */
- ED_gpencil_parent_location(gpl, diff_mat);
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- mul_m4_v3(diff_mat, &pt->x);
- }
- }
- }
- }
/* clear parent */
gpl->parent = NULL;
}
@@ -306,6 +296,15 @@ static void rna_GPencil_active_layer_set(PointerRNA *ptr, PointerRNA value)
{
bGPdata *gpd = ptr->id.data;
+ /* Don't allow setting active layer to NULL if layers exist
+ * as this breaks various tools. Tools should be used instead
+ * if it's necessary to remove layers
+ */
+ if (value.data == NULL) {
+ printf("%s: Setting active layer to None is not allowed\n", __func__);
+ return;
+ }
+
if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */
bGPDlayer *gl;
@@ -349,6 +348,36 @@ static void rna_GPencil_active_layer_index_range(PointerRNA *ptr, int *min, int
*softmax = *max;
}
+static const EnumPropertyItem *rna_GPencil_active_layer_itemf(
+ bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ bGPdata *gpd = (bGPdata *)ptr->id.data;
+ bGPDlayer *gpl;
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+ int i = 0;
+
+ if (ELEM(NULL, C, gpd)) {
+ return DummyRNA_NULL_items;
+ }
+
+ /* Existing layers */
+ for (gpl = gpd->layers.first, i = 0; gpl; gpl = gpl->next, i++) {
+ item_tmp.identifier = gpl->info;
+ item_tmp.name = gpl->info;
+ item_tmp.value = i;
+
+ item_tmp.icon = BKE_icon_gplayer_color_ensure(gpl);
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value)
{
bGPdata *gpd = ptr->id.data;
@@ -366,31 +395,6 @@ static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value)
BKE_animdata_fix_paths_rename_all(&gpd->id, "layers", oldname, gpl->info);
}
-static void rna_GPencil_use_onion_skinning_set(PointerRNA *ptr, const bool value)
-{
- bGPdata *gpd = ptr->id.data;
- bGPDlayer *gpl;
-
- /* set new value */
- if (value) {
- /* enable on active layer (it's the one that's most likely to be of interest right now) */
- gpl = BKE_gpencil_layer_getactive(gpd);
- if (gpl) {
- gpl->flag |= GP_LAYER_ONIONSKIN;
- }
-
- gpd->flag |= GP_DATA_SHOW_ONIONSKINS;
- }
- else {
- /* disable on all layers - allowa quickly turning them all off, without having to check */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- gpl->flag &= ~GP_LAYER_ONIONSKIN;
- }
-
- gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS;
- }
-}
-
static bGPDstroke *rna_GPencil_stroke_point_find_stroke(const bGPdata *gpd, const bGPDspoint *pt, bGPDlayer **r_gpl, bGPDframe **r_gpf)
{
bGPDlayer *gpl;
@@ -454,14 +458,21 @@ static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count, float pr
stroke->points = MEM_recallocN_id(stroke->points,
sizeof(bGPDspoint) * (stroke->totpoints + count),
"gp_stroke_points");
+ stroke->dvert = MEM_recallocN_id(stroke->dvert,
+ sizeof(MDeformVert) * (stroke->totpoints + count),
+ "gp_stroke_weight");
/* init the pressure and strength values so that old scripts won't need to
* be modified to give these initial values...
*/
for (int i = 0; i < count; i++) {
bGPDspoint *pt = stroke->points + (stroke->totpoints + i);
+ MDeformVert *dvert = stroke->dvert + (stroke->totpoints + i);
pt->pressure = pressure;
pt->strength = strength;
+
+ dvert->totweight = 0;
+ dvert->dw = NULL;
}
stroke->totpoints += count;
@@ -471,6 +482,7 @@ static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count, float pr
static void rna_GPencil_stroke_point_pop(bGPDstroke *stroke, ReportList *reports, int index)
{
bGPDspoint *pt_tmp = stroke->points;
+ MDeformVert *pt_dvert = stroke->dvert;
/* python style negative indexing */
if (index < 0) {
@@ -485,27 +497,35 @@ static void rna_GPencil_stroke_point_pop(bGPDstroke *stroke, ReportList *reports
stroke->totpoints--;
stroke->points = MEM_callocN(sizeof(bGPDspoint) * stroke->totpoints, "gp_stroke_points");
+ stroke->dvert = MEM_callocN(sizeof(MDeformVert) * stroke->totpoints, "gp_stroke_weights");
- if (index > 0)
+ if (index > 0) {
memcpy(stroke->points, pt_tmp, sizeof(bGPDspoint) * index);
+ /* verify weight data is available */
+ if (pt_dvert != NULL) {
+ memcpy(stroke->dvert, pt_dvert, sizeof(MDeformVert) * index);
+ }
+ }
- if (index < stroke->totpoints)
+ if (index < stroke->totpoints) {
memcpy(&stroke->points[index], &pt_tmp[index + 1], sizeof(bGPDspoint) * (stroke->totpoints - index));
+ if (pt_dvert != NULL) {
+ memcpy(&stroke->dvert[index], &pt_dvert[index + 1], sizeof(MDeformVert) * (stroke->totpoints - index));
+ }
+ }
/* free temp buffer */
MEM_freeN(pt_tmp);
+ if (pt_dvert != NULL) {
+ MEM_freeN(pt_dvert);
+ }
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
-static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame, const char *colorname)
+static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame)
{
bGPDstroke *stroke = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
- if (colorname) {
- BLI_strncpy(stroke->colorname, colorname, sizeof(stroke->colorname));
- }
- stroke->palcolor = NULL;
- stroke->flag |= GP_STROKE_RECALC_COLOR;
BLI_addtail(&frame->strokes, stroke);
return stroke;
@@ -635,260 +655,18 @@ static void rna_GPencil_clear(bGPdata *gpd)
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
-/* Palettes */
-static bGPDpalette *rna_GPencil_palette_new(bGPdata *gpd, const char *name, bool setactive)
-{
- bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, name, setactive != 0);
-
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return palette;
-}
-
-static void rna_GPencil_palette_remove(bGPdata *gpd, ReportList *reports, PointerRNA *palette_ptr)
-{
- bGPDpalette *palette = palette_ptr->data;
- if (BLI_findindex(&gpd->palettes, palette) == -1) {
- BKE_report(reports, RPT_ERROR, "Palette not found in grease pencil data");
- return;
- }
-
- BKE_gpencil_palette_delete(gpd, palette);
- RNA_POINTER_INVALIDATE(palette_ptr);
-
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-}
-
-static PointerRNA rna_GPencil_active_palette_get(PointerRNA *ptr)
-{
- bGPdata *gpd = ptr->id.data;
-
- if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */
- bGPDpalette *palette;
-
- for (palette = gpd->palettes.first; palette; palette = palette->next) {
- if (palette->flag & PL_PALETTE_ACTIVE) {
- break;
- }
- }
-
- if (palette) {
- return rna_pointer_inherit_refine(ptr, &RNA_GPencilPalette, palette);
- }
- }
-
- return rna_pointer_inherit_refine(ptr, NULL, NULL);
-}
-
-static void rna_GPencil_active_palette_set(PointerRNA *ptr, PointerRNA value)
-{
- bGPdata *gpd = ptr->id.data;
-
- if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */
- bGPDpalette *palette;
-
- for (palette = gpd->palettes.first; palette; palette = palette->next) {
- if (palette == value.data) {
- palette->flag |= PL_PALETTE_ACTIVE;
- }
- else {
- palette->flag &= ~PL_PALETTE_ACTIVE;
- }
- }
- /* force color recalc */
- BKE_gpencil_palette_change_strokes(gpd);
-
- WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
- }
-}
-
-static int rna_GPencilPalette_index_get(PointerRNA *ptr)
-{
- bGPdata *gpd = (bGPdata *)ptr->id.data;
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
-
- return BLI_findindex(&gpd->palettes, palette);
-}
-
-static void rna_GPencilPalette_index_set(PointerRNA *ptr, int value)
-{
- bGPdata *gpd = (bGPdata *)ptr->id.data;
- bGPDpalette *palette = BLI_findlink(&gpd->palettes, value);
-
- BKE_gpencil_palette_setactive(gpd, palette);
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-}
-
-static void rna_GPencilPalette_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
-{
- bGPdata *gpd = (bGPdata *)ptr->id.data;
-
- *min = 0;
- *max = max_ii(0, BLI_listbase_count(&gpd->palettes) - 1);
-
- *softmin = *min;
- *softmax = *max;
-}
-
-/* Palette colors */
-static bGPDpalettecolor *rna_GPencilPalette_color_new(bGPDpalette *palette)
-{
- bGPDpalettecolor *color = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
-
- return color;
-}
-
-static void rna_GPencilPalette_color_remove(bGPDpalette *palette, ReportList *reports, PointerRNA *color_ptr)
-{
- bGPDpalettecolor *color = color_ptr->data;
-
- if (BLI_findindex(&palette->colors, color) == -1) {
- BKE_reportf(reports, RPT_ERROR, "Palette '%s' does not contain color given", palette->info + 2);
- return;
- }
-
- BKE_gpencil_palettecolor_delete(palette, color);
- RNA_POINTER_INVALIDATE(color_ptr);
-
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-}
-
-static PointerRNA rna_GPencilPalette_active_color_get(PointerRNA *ptr)
-{
- bGPDpalette *palette = (bGPDpalette *)ptr->data;
- bGPDpalettecolor *color;
-
- for (color = palette->colors.first; color; color = color->next) {
- if (color->flag & PC_COLOR_ACTIVE) {
- break;
- }
- }
-
- if (color) {
- return rna_pointer_inherit_refine(ptr, &RNA_GPencilPaletteColor, color);
- }
-
- return rna_pointer_inherit_refine(ptr, NULL, NULL);
-}
-
-static void rna_GPencilPalette_active_color_set(PointerRNA *ptr, PointerRNA value)
-{
- bGPDpalette *palette = (bGPDpalette *)ptr->data;
- bGPDpalettecolor *color = value.data;
-
- BKE_gpencil_palettecolor_setactive(palette, color);
-}
-
-static void rna_GPencilPalette_info_set(PointerRNA *ptr, const char *value)
-{
- bGPdata *gpd = ptr->id.data;
- bGPDpalette *palette = ptr->data;
-
- char oldname[64] = "";
- BLI_strncpy(oldname, palette->info, sizeof(oldname));
-
- /* copy the new name into the name slot */
- BLI_strncpy_utf8(palette->info, value, sizeof(palette->info));
-
- BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info),
- sizeof(palette->info));
- /* now fix animation paths */
- BKE_animdata_fix_paths_rename_all(&gpd->id, "palettes", oldname, palette->info);
-}
-
-static char *rna_GPencilPalette_path(PointerRNA *ptr)
-{
- bGPDpalette *palette = ptr->data;
- char name_esc[sizeof(palette->info) * 2];
-
- BLI_strescape(name_esc, palette->info, sizeof(name_esc));
-
- return BLI_sprintfN("palettes[\"%s\"]", name_esc);
-}
-
-static char *rna_GPencilPalette_color_path(PointerRNA *ptr)
-{
- bGPdata *gpd = ptr->id.data;
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = ptr->data;
-
- char name_palette[sizeof(palette->info) * 2];
- char name_color[sizeof(palcolor->info) * 2];
-
- BLI_strescape(name_palette, palette->info, sizeof(name_palette));
- BLI_strescape(name_color, palcolor->info, sizeof(name_color));
-
- return BLI_sprintfN("palettes[\"%s\"].colors[\"%s\"]", name_palette, name_color);
-}
-
-static void rna_GPencilPaletteColor_info_set(PointerRNA *ptr, const char *value)
-{
- bGPdata *gpd = ptr->id.data;
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = ptr->data;
-
- char oldname[64] = "";
- BLI_strncpy(oldname, palcolor->info, sizeof(oldname));
-
- /* copy the new name into the name slot */
- BLI_strncpy_utf8(palcolor->info, value, sizeof(palcolor->info));
- BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
- sizeof(palcolor->info));
-
- /* rename all strokes */
- BKE_gpencil_palettecolor_changename(gpd, oldname, palcolor->info);
-
- /* now fix animation paths */
- BKE_animdata_fix_paths_rename_all(&gpd->id, "colors", oldname, palcolor->info);
-}
-
-static void rna_GPencilStrokeColor_info_set(PointerRNA *ptr, const char *value)
+static void rna_GpencilVertex_groups_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
bGPDstroke *gps = ptr->data;
- /* copy the new name into the name slot */
- BLI_strncpy_utf8(gps->colorname, value, sizeof(gps->colorname));
-}
+ if (gps->dvert) {
+ MDeformVert *dvert = gps->dvert;
-
-static bool rna_GPencilPaletteColor_is_stroke_visible_get(PointerRNA *ptr)
-{
- bGPDpalettecolor *pcolor = (bGPDpalettecolor *)ptr->data;
- return (pcolor->color[3] > GPENCIL_ALPHA_OPACITY_THRESH);
-}
-
-static bool rna_GPencilPaletteColor_is_fill_visible_get(PointerRNA *ptr)
-{
- bGPDpalettecolor *pcolor = (bGPDpalettecolor *)ptr->data;
- return (pcolor->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH);
-}
-
-static int rna_GPencilPaletteColor_index_get(PointerRNA *ptr)
-{
- bGPDpalette *palette = (bGPDpalette *)ptr->data;
- bGPDpalettecolor *pcolor = BKE_gpencil_palettecolor_getactive(palette);
-
- return BLI_findindex(&palette->colors, pcolor);
-}
-
-static void rna_GPencilPaletteColor_index_set(PointerRNA *ptr, int value)
-{
- bGPDpalette *palette = (bGPDpalette *)ptr->data;
- bGPDpalettecolor *pcolor = BLI_findlink(&palette->colors, value);
- BKE_gpencil_palettecolor_setactive(palette, pcolor);
-}
-
-static void rna_GPencilPaletteColor_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
-{
- bGPDpalette *palette = (bGPDpalette *)ptr->data;
-
- *min = 0;
- *max = max_ii(0, BLI_listbase_count(&palette->colors) - 1);
-
- *softmin = *min;
- *softmax = *max;
+ rna_iterator_array_begin(iter, (void *)dvert->dw, sizeof(MDeformWeight), dvert->totweight, 0, NULL);
+ }
+ else
+ rna_iterator_array_begin(iter, NULL, 0, 0, 0, NULL);
}
-
#else
static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
@@ -918,11 +696,24 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Strength", "Color intensity (alpha factor)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "uv_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "uv_fac");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "UV Factor", "Internal UV factor");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "uv_rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "uv_rot");
+ RNA_def_property_range(prop, 0.0f, M_PI * 2);
+ RNA_def_property_ui_text(prop, "UV Rotation", "Internal UV factor for dot mode");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SPOINT_SELECT);
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");
+
}
static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cprop)
@@ -955,7 +746,7 @@ static void rna_def_gpencil_triangle(BlenderRNA *brna)
srna = RNA_def_struct(brna, "GPencilTriangle", NULL);
RNA_def_struct_sdna(srna, "bGPDtriangle");
- RNA_def_struct_ui_text(srna, "Triangle", "Triangulation data for HQ fill");
+ RNA_def_struct_ui_text(srna, "Triangle", "Triangulation data for Grease Pencil fills");
/* point v1 */
prop = RNA_def_property(srna, "v1", PROP_INT, PROP_NONE);
@@ -974,6 +765,51 @@ 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)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "GpencilVertexGroupElement", NULL);
+ RNA_def_struct_sdna(srna, "MDeformWeight");
+ RNA_def_struct_ui_text(srna, "Vertex Group Element", "Weight value of a vertex in a vertex group");
+ RNA_def_struct_ui_icon(srna, ICON_GROUP_VERTEX);
+
+ /* we can't point to actual group, it is in the object and so
+ * there is no unique group to point to, hence the index */
+ prop = RNA_def_property(srna, "group", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "def_nr");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Group Index", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Weight", "Vertex Weight");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
}
static void rna_def_gpencil_stroke(BlenderRNA *brna)
@@ -1000,24 +836,30 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Stroke Points", "Stroke data points");
rna_def_gpencil_stroke_points_api(brna, prop);
+ /* vertex groups */
+ prop = RNA_def_property(srna, "groups", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_funcs(prop, "rna_GpencilVertex_groups_begin", "rna_iterator_array_next",
+ "rna_iterator_array_end", "rna_iterator_array_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "GpencilVertexGroupElement");
+ RNA_def_property_ui_text(prop, "Groups", "Weights for the vertex groups this vertex is member of");
+
/* Triangles */
prop = RNA_def_property(srna, "triangles", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "triangles", "tot_triangles");
RNA_def_property_struct_type(prop, "GPencilTriangle");
RNA_def_property_ui_text(prop, "Triangles", "Triangulation data for HQ fill");
- /* Color */
- prop = RNA_def_property(srna, "color", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "GPencilPaletteColor");
- RNA_def_property_pointer_sdna(prop, NULL, "palcolor");
- RNA_def_property_ui_text(prop, "Palette Color", "Color from palette used in Stroke");
- RNA_def_property_update(prop, 0, "rna_GPencil_update");
+ /* Material Index */
+ prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "mat_nr");
+ RNA_def_property_ui_text(prop, "Material Index", "Index of material used in this stroke");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Settings */
prop = RNA_def_property(srna, "draw_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, stroke_draw_mode_items);
- RNA_def_property_ui_text(prop, "Draw Mode", "");
+ RNA_def_property_ui_text(prop, "Draw Mode", "Coordinate space that stroke is in");
RNA_def_property_update(prop, 0, "rna_GPencil_update");
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
@@ -1026,22 +868,23 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Select", "Stroke is selected for viewport editing");
RNA_def_property_update(prop, 0, "rna_GPencil_update");
- /* Color Name */
- prop = RNA_def_property(srna, "colorname", PROP_STRING, PROP_NONE);
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilStrokeColor_info_set");
- RNA_def_property_ui_text(prop, "Color Name", "Palette color name");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_colorname_update");
-
/* Cyclic: Draw a line from end to start point */
prop = RNA_def_property(srna, "draw_cyclic", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STROKE_CYCLIC);
RNA_def_property_ui_text(prop, "Cyclic", "Enable cyclic drawing, closing the stroke");
RNA_def_property_update(prop, 0, "rna_GPencil_update");
+ /* No fill: The stroke never must fill area and must use fill color as stroke color (this is a special flag for fill brush) */
+ prop = RNA_def_property(srna, "is_nofill_stroke", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STROKE_NOFILL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "No Fill", "Special stroke to use as boundary for filling areas");
+ RNA_def_property_update(prop, 0, "rna_GPencil_update");
+
/* Line Thickness */
prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "thickness");
- RNA_def_property_range(prop, 1, 300);
+ RNA_def_property_range(prop, 1, 1000);
RNA_def_property_ui_range(prop, 1, 10, 1, 0);
RNA_def_property_ui_text(prop, "Thickness", "Thickness of stroke (in pixels)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
@@ -1062,7 +905,6 @@ static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_GPencil_stroke_new");
RNA_def_function_ui_description(func, "Add a new grease pencil stroke");
- parm = RNA_def_string(func, "colorname", 0, MAX_NAME, "Color", "Name of the color");
parm = RNA_def_pointer(func, "stroke", "GPencilStroke", "", "The newly created stroke");
RNA_def_function_return(func, parm);
@@ -1183,20 +1025,30 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_editable_func(prop, "rna_GPencilLayer_active_frame_editable");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- /* Draw Style */
- // TODO: replace these with a "draw type" combo (i.e. strokes only, filled strokes, strokes + fills, volumetric)?
- prop = RNA_def_property(srna, "use_volumetric_strokes", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_VOLUMETRIC);
- RNA_def_property_ui_text(prop, "Volumetric Strokes",
- "Draw strokes as a series of circular blobs, resulting in a volumetric effect");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ /* Layer Opacity */
prop = RNA_def_property(srna, "opacity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "opacity");
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_text(prop, "Opacity", "Layer Opacity");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Stroke Drawing Color (Annotations) */
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Color", "Color for all strokes in this layer");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Line Thickness (Annotations) */
+ prop = RNA_def_property(srna, "thickness", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "thickness");
+ RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_ui_text(prop, "Thickness", "Thickness of annotation strokes");
+ 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);
RNA_def_property_float_sdna(prop, NULL, "tintcolor");
@@ -1212,62 +1064,21 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Tint Factor", "Factor of tinting color");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- /* Line Thickness change */
+ /* Line Thickness Change */
prop = RNA_def_property(srna, "line_change", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "thickness");
- //RNA_def_property_range(prop, 1, 10); /* 10 px limit comes from Windows OpenGL limits for natively-drawn strokes */
- RNA_def_property_int_funcs(prop, NULL, NULL, "rna_GPencilLayer_line_width_range");
- RNA_def_property_ui_text(prop, "Thickness", "Thickness change to apply to current strokes (in pixels)");
+ RNA_def_property_int_sdna(prop, NULL, "line_change");
+ RNA_def_property_range(prop, -300, 300);
+ RNA_def_property_ui_range(prop, -100, 100, 1.0, 1);
+ RNA_def_property_ui_text(prop, "Thickness Change", "Thickness change to apply to current strokes (in pixels)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* Onion-Skinning */
prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_ONIONSKIN);
+ RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_LAYER_ONIONSKIN);
RNA_def_property_ui_text(prop, "Onion Skinning", "Ghost frames on either side of frame");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_onion_skinning_update");
-
- prop = RNA_def_property(srna, "ghost_before_range", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "gstep");
- RNA_def_property_range(prop, -1, 120);
- RNA_def_property_ui_text(prop, "Frames Before",
- "Maximum number of frames to show before current frame "
- "(0 = show only the previous sketch, -1 = don't show any frames before current)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- prop = RNA_def_property(srna, "ghost_after_range", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "gstep_next");
- RNA_def_property_range(prop, -1, 120);
- RNA_def_property_ui_text(prop, "Frames After",
- "Maximum number of frames to show after current frame "
- "(0 = show only the next sketch, -1 = don't show any frames after current)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- prop = RNA_def_property(srna, "use_ghost_custom_colors", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_GHOST_PREVCOL | GP_LAYER_GHOST_NEXTCOL);
- 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);
- RNA_def_property_float_sdna(prop, NULL, "gcolor_prev");
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Before Color", "Base color for ghosts before the active frame");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- prop = RNA_def_property(srna, "after_color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "gcolor_next");
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- prop = RNA_def_property(srna, "use_ghosts_always", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_GHOST_ALWAYS);
- RNA_def_property_ui_text(prop, "Always Show Ghosts",
- "Ghosts are shown in renders and animation playback. Useful for special effects (e.g. motion blur)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
-
/* Flags */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE);
@@ -1296,7 +1107,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- /* expose as layers.active */
+ /* 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);
@@ -1310,7 +1121,6 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Select", "Layer is selected for editing in the Dope Sheet");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, "rna_GPencil_update");
- /* XXX keep this option? */
prop = RNA_def_property(srna, "show_points", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_DRAWDEBUG);
RNA_def_property_ui_text(prop, "Show Points", "Draw the points which make up the strokes (for debugging purposes)");
@@ -1399,215 +1209,24 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop,
- "rna_GPencil_active_layer_index_get",
- "rna_GPencil_active_layer_index_set",
- "rna_GPencil_active_layer_index_range");
+ RNA_def_property_int_funcs(
+ prop,
+ "rna_GPencil_active_layer_index_get",
+ "rna_GPencil_active_layer_index_set",
+ "rna_GPencil_active_layer_index_range");
RNA_def_property_ui_text(prop, "Active Layer Index", "Index of active grease pencil layer");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
-}
-
-static void rna_def_gpencil_palettecolor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
- srna = RNA_def_struct(brna, "GPencilPaletteColor", NULL);
- RNA_def_struct_sdna(srna, "bGPDpalettecolor");
- RNA_def_struct_ui_text(srna, "Grease Pencil Palette color", "Collection of related colors");
- RNA_def_struct_path_func(srna, "rna_GPencilPalette_color_path");
-
- /* Stroke Drawing Color */
- prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "color");
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Color", "Color for strokes");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "color[3]");
- RNA_def_property_range(prop, 0.0, 1.0f);
- RNA_def_property_ui_text(prop, "Opacity", "Color Opacity");
+ /* Active Layer - As an enum (for selecting active layer for annotations) */
+ prop = RNA_def_property(srna, "active_note", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_funcs(
+ prop,
+ "rna_GPencil_active_layer_index_get",
+ "rna_GPencil_active_layer_index_set",
+ "rna_GPencil_active_layer_itemf");
+ RNA_def_property_enum_items(prop, DummyRNA_DEFAULT_items); /* purely dynamic, as it maps to user-data */
+ RNA_def_property_ui_text(prop, "Active Note", "Note/Layer to add annotation strokes to");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Name */
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "info");
- RNA_def_property_ui_text(prop, "Name", "Color name");
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilPaletteColor_info_set");
- RNA_def_struct_name_property(srna, prop);
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Fill Drawing Color */
- prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "fill");
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Fill Color", "Color for filling region bounded by each stroke");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Fill alpha */
- prop = RNA_def_property(srna, "fill_alpha", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "fill[3]");
- RNA_def_property_range(prop, 0.0, 1.0f);
- RNA_def_property_ui_text(prop, "Fill Opacity", "Opacity for filling region bounded by each stroke");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Flags */
- prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_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_DATA, "rna_GPencil_update");
-
- prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_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_DATA, "rna_GPencil_update");
-
- prop = RNA_def_property(srna, "ghost", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_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_DATA, "rna_GPencil_update");
-
- /* Draw Style */
- prop = RNA_def_property(srna, "use_volumetric_strokes", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_VOLUMETRIC);
- RNA_def_property_ui_text(prop, "Volumetric Strokes", "Draw strokes as a series of circular blobs, resulting in "
- "a volumetric effect");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Use High quality fill */
- prop = RNA_def_property(srna, "use_hq_fill", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_HQ_FILL);
- RNA_def_property_ui_text(prop, "High Quality Fill", "Fill strokes using high quality to avoid glitches "
- "(slower fps during animation play)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Read-only state props (for simpler UI code) */
- prop = RNA_def_property(srna, "is_stroke_visible", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_GPencilPaletteColor_is_stroke_visible_get", NULL);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Is Stroke Visible", "True when opacity of stroke is set high enough to be visible");
-
- prop = RNA_def_property(srna, "is_fill_visible", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_GPencilPaletteColor_is_fill_visible_get", NULL);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Is Fill Visible", "True when opacity of fill is set high enough to be visible");
-}
-
-/* palette colors api */
-static void rna_def_gpencil_palettecolors_api(BlenderRNA *brna, PropertyRNA *cprop)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- FunctionRNA *func;
- PropertyRNA *parm;
-
- RNA_def_property_srna(cprop, "GPencilPaletteColors");
- srna = RNA_def_struct(brna, "GPencilPaletteColors", NULL);
- RNA_def_struct_sdna(srna, "bGPDpalette");
- RNA_def_struct_ui_text(srna, "Palette colors", "Collection of palette colors");
-
- func = RNA_def_function(srna, "new", "rna_GPencilPalette_color_new");
- RNA_def_function_ui_description(func, "Add a new color to the palette");
- parm = RNA_def_pointer(func, "color", "GPencilPaletteColor", "", "The newly created color");
- RNA_def_function_return(func, parm);
-
- func = RNA_def_function(srna, "remove", "rna_GPencilPalette_color_remove");
- RNA_def_function_ui_description(func, "Remove a color from the palette");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "color", "GPencilPaletteColor", "", "The color to remove");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
- RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
-
- prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "GPencilPaletteColor");
- RNA_def_property_pointer_funcs(prop, "rna_GPencilPalette_active_color_get", "rna_GPencilPalette_active_color_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Active Palette Color", "Current active color");
-
- prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop,
- "rna_GPencilPaletteColor_index_get",
- "rna_GPencilPaletteColor_index_set",
- "rna_GPencilPaletteColor_index_range");
- RNA_def_property_ui_text(prop, "Active color Index", "Index of active palette color");
-}
-
-static void rna_def_gpencil_palette(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "GPencilPalette", NULL);
- RNA_def_struct_sdna(srna, "bGPDpalette");
- RNA_def_struct_ui_text(srna, "Grease Pencil Palette", "Collection of related palettes");
- RNA_def_struct_path_func(srna, "rna_GPencilPalette_path");
- RNA_def_struct_ui_icon(srna, ICON_COLOR);
-
- /* Name */
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "info");
- RNA_def_property_ui_text(prop, "Name", "Palette name");
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilPalette_info_set");
- RNA_def_struct_name_property(srna, prop);
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Colors */
- prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "colors", NULL);
- RNA_def_property_struct_type(prop, "GPencilPaletteColor");
- RNA_def_property_ui_text(prop, "Colors", "Colors of the palette");
- rna_def_gpencil_palettecolors_api(brna, prop);
-
-}
-
-static void rna_def_gpencil_palettes_api(BlenderRNA *brna, PropertyRNA *cprop)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- FunctionRNA *func;
- PropertyRNA *parm;
-
- RNA_def_property_srna(cprop, "GreasePencilPalettes");
- srna = RNA_def_struct(brna, "GreasePencilPalettes", NULL);
- RNA_def_struct_sdna(srna, "bGPdata");
- RNA_def_struct_ui_text(srna, "Grease Pencil Palettes", "Collection of grease pencil palettes");
-
- func = RNA_def_function(srna, "new", "rna_GPencil_palette_new");
- RNA_def_function_ui_description(func, "Add a new grease pencil palette");
- parm = RNA_def_string(func, "name", "GPencilPalette", MAX_NAME, "Name", "Name of the palette");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- RNA_def_boolean(func, "set_active", true, "Set Active", "Activate the newly created palette");
- parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The newly created palette");
- RNA_def_function_return(func, parm);
-
- func = RNA_def_function(srna, "remove", "rna_GPencil_palette_remove");
- RNA_def_function_ui_description(func, "Remove a grease pencil palette");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The palette to remove");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
- RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
-
- prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "GPencilPalette");
- RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_palette_get", "rna_GPencil_active_palette_set",
- NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Active Palette", "Current active palette");
-
- prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop,
- "rna_GPencilPalette_index_get",
- "rna_GPencilPalette_index_set",
- "rna_GPencilPalette_index_range");
- RNA_def_property_ui_text(prop, "Active Palette Index", "Index of active palette");
}
static void rna_def_gpencil_data(BlenderRNA *brna)
@@ -1616,6 +1235,10 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
PropertyRNA *prop;
FunctionRNA *func;
+ static float default_1[4] = { 0.6f, 0.6f, 0.6f, 0.5f };
+ static float onion_dft1[3] = { 0.145098f, 0.419608f, 0.137255f }; /* green */
+ static float onion_dft2[3] = { 0.125490f, 0.082353f, 0.529412f }; /* blue */
+
srna = RNA_def_struct(brna, "GreasePencil", "ID");
RNA_def_struct_sdna(srna, "bGPdata");
RNA_def_struct_ui_text(srna, "Grease Pencil", "Freehand annotation sketchbook");
@@ -1628,28 +1251,52 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layers", "");
rna_def_gpencil_layers_api(brna, prop);
- /* Palettes */
- prop = RNA_def_property(srna, "palettes", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "palettes", NULL);
- RNA_def_property_struct_type(prop, "GPencilPalette");
- RNA_def_property_ui_text(prop, "Palettes", "");
- rna_def_gpencil_palettes_api(brna, prop);
-
/* Animation Data */
rna_def_animdata_common(srna);
+ /* materials */
+ prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
+ RNA_def_property_struct_type(prop, "Material");
+ RNA_def_property_ui_text(prop, "Materials", "");
+ RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */
+ RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int");
+
+ /* xray modes */
+ prop = RNA_def_property(srna, "xray_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "xray_mode");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_xraymodes_items);
+ RNA_def_property_ui_text(prop, "Xray", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* Flags */
prop = RNA_def_property(srna, "use_stroke_edit_mode", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_EDITMODE);
RNA_def_property_ui_text(prop, "Stroke Edit Mode", "Edit Grease Pencil strokes instead of viewport data");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_editmode_update");
+ prop = RNA_def_property(srna, "is_stroke_paint_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_PAINTMODE);
+ RNA_def_property_ui_text(prop, "Stroke Paint Mode", "Draw Grease Pencil strokes on click/drag");
+ 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, "is_stroke_sculpt_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_SCULPTMODE);
+ RNA_def_property_ui_text(prop, "Stroke Sculpt Mode", "Sculpt Grease Pencil strokes instead of viewport data");
+ 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, "is_stroke_weight_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_WEIGHTMODE);
+ RNA_def_property_ui_text(prop, "Stroke Weight Paint Mode", "Grease Pencil weight 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_funcs(prop, NULL, "rna_GPencil_use_onion_skinning_set");
- RNA_def_property_ui_text(prop, "Onion Skins",
- "Show ghosts of the frames before and after the current frame, toggle to enable on active layer or disable all");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ RNA_def_property_ui_text(prop, "Onion Skins", "Show ghosts of the frames before and after the current frame");
+ 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);
@@ -1657,6 +1304,102 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
"and smaller red dot (end) points");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "show_constant_thickness", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_KEEPTHICKNESS);
+ RNA_def_property_ui_text(prop, "Keep thickness", "Show stroke with same thickness when viewport zoom change");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "pixfactor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "pixfactor");
+ RNA_def_property_range(prop, 0.1f, 30.0f);
+ RNA_def_property_ui_range(prop, 0.1f, 30.0f, 1, 2);
+ RNA_def_property_ui_text(prop, "Scale", "Scale conversion factor for pixel size (use larger values for thicker lines)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_multiedit", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_MULTIEDIT);
+ RNA_def_property_ui_text(prop, "MultiFrame", "Edit strokes from multiple grease pencil keyframes at the same time (keyframes must be selected to be included)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "edit_line_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "line_color");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_array_default(prop, default_1);
+ RNA_def_property_ui_text(prop, "Edit Line Color", "Color for editing line");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* onion skinning */
+ prop = RNA_def_property(srna, "ghost_before_range", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "gstep");
+ RNA_def_property_range(prop, 0, 120);
+ RNA_def_property_int_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Frames Before",
+ "Maximum number of frames to show before current frame "
+ "(0 = don't show any frames before current)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "ghost_after_range", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "gstep_next");
+ RNA_def_property_range(prop, 0, 120);
+ RNA_def_property_int_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Frames After",
+ "Maximum number of frames to show after current frame "
+ "(0 = don't show any frames after current)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_ghost_custom_colors", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL);
+ 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);
+ RNA_def_property_float_sdna(prop, NULL, "gcolor_prev");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_array_default(prop, onion_dft1);
+ RNA_def_property_ui_text(prop, "Before Color", "Base color for ghosts before the active frame");
+ 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);
+ RNA_def_property_float_sdna(prop, NULL, "gcolor_next");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_array_default(prop, onion_dft2);
+ RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame");
+ RNA_def_property_update(prop, NC_SCREEN | NC_SCENE | ND_TOOLSETTINGS | ND_DATA | NC_GPENCIL, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_ghosts_always", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_GHOST_ALWAYS);
+ RNA_def_property_ui_text(prop, "Always Show Ghosts",
+ "Ghosts are shown in renders and animation playback. Useful for special effects (e.g. motion blur)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "onion_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "onion_mode");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_onion_modes_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode to display frames");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_onion_fade", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_FADE);
+ RNA_def_property_ui_text(prop, "Fade",
+ "Display onion keyframes with a fade in color transparency");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ 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_property_ui_text(prop, "Loop",
+ "Display first onion keyframes using next frame color to show indication of loop start frame");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "onion_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "onion_factor");
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_range(prop, 0.0, 1.0f);
+ RNA_def_property_ui_text(prop, "Onion Opacity", "Change fade opacity of displayed onion frames");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* API Functions */
func = RNA_def_function(srna, "clear", "rna_GPencil_clear");
RNA_def_function_ui_description(func, "Remove all the grease pencil data");
@@ -1670,12 +1413,12 @@ void RNA_def_gpencil(BlenderRNA *brna)
rna_def_gpencil_layer(brna);
rna_def_gpencil_frame(brna);
- rna_def_gpencil_triangle(brna);
+
rna_def_gpencil_stroke(brna);
rna_def_gpencil_stroke_point(brna);
+ rna_def_gpencil_triangle(brna);
- rna_def_gpencil_palette(brna);
- rna_def_gpencil_palettecolor(brna);
+ rna_def_gpencil_mvert_group(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
new file mode 100644
index 00000000000..df64121b2b4
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -0,0 +1,1314 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_gpencil_modifier.c
+ * \ingroup RNA
+ */
+
+
+#include <float.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_cachefile_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_animsys.h"
+#include "BKE_data_transfer.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_dynamicpaint.h"
+#include "BKE_effect.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_remap.h"
+#include "BKE_multires.h"
+#include "BKE_smoke.h" /* For smokeModifier_free & smokeModifier_createType */
+#include "BKE_gpencil_modifier.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
+ {0, "", 0, N_("Generate"), "" },
+ {eGpencilModifierType_Instance, "GP_INSTANCE", ICON_MOD_ARRAY, "Instance", "Create grid of duplicate instances"},
+ {eGpencilModifierType_Build, "GP_BUILD", ICON_MOD_BUILD, "Build", "Create duplication of strokes"},
+ {eGpencilModifierType_Simplify, "GP_SIMPLIFY", ICON_MOD_DECIM, "Simplify", "Simplify stroke reducing number of points"},
+ {eGpencilModifierType_Subdiv, "GP_SUBDIV", ICON_MOD_SUBSURF, "Subdivide", "Subdivide stroke adding more control points"},
+ {0, "", 0, N_("Deform"), "" },
+ {eGpencilModifierType_Hook, "GP_HOOK", ICON_HOOK, "Hook", "Deform stroke points using objects"},
+ {eGpencilModifierType_Lattice, "GP_LATTICE", ICON_MOD_LATTICE, "Lattice", "Deform strokes using lattice"},
+ {eGpencilModifierType_Mirror, "GP_MIRROR", ICON_MOD_MIRROR, "Mirror", "Duplicate strokes like a mirror"},
+ {eGpencilModifierType_Noise, "GP_NOISE", ICON_RNDCURVE, "Noise", "Add noise to strokes"},
+ {eGpencilModifierType_Offset, "GP_OFFSET", ICON_MOD_DISPLACE, "Offset", "Change stroke location, rotation or scale"},
+ {eGpencilModifierType_Smooth, "GP_SMOOTH", ICON_MOD_SMOOTH, "Smooth", "Smooth stroke"},
+ {eGpencilModifierType_Thick, "GP_THICK", ICON_MAN_ROT, "Thickness", "Change stroke thickness"},
+ {0, "", 0, N_("Color"), "" },
+ {eGpencilModifierType_Color, "GP_COLOR", ICON_GROUP_VCOL, "Hue/Saturation", "Apply changes to stroke colors"},
+ {eGpencilModifierType_Opacity, "GP_OPACITY", ICON_MOD_MASK, "Opacity", "Opacity of the strokes"},
+ {eGpencilModifierType_Tint, "GP_TINT", ICON_COLOR, "Tint", "Tint strokes with new color"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+#ifndef RNA_RUNTIME
+static const EnumPropertyItem modifier_gphook_falloff_items[] = {
+ { eGPHook_Falloff_None, "NONE", 0, "No Falloff", "" },
+ { eGPHook_Falloff_Curve, "CURVE", 0, "Curve", "" },
+ { eGPHook_Falloff_Smooth, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", "" },
+ { eGPHook_Falloff_Sphere, "SPHERE", ICON_SPHERECURVE, "Sphere", "" },
+ { eGPHook_Falloff_Root, "ROOT", ICON_ROOTCURVE, "Root", "" },
+ { eGPHook_Falloff_InvSquare, "INVERSE_SQUARE", ICON_ROOTCURVE, "Inverse Square", "" },
+ { eGPHook_Falloff_Sharp, "SHARP", ICON_SHARPCURVE, "Sharp", "" },
+ { eGPHook_Falloff_Linear, "LINEAR", ICON_LINCURVE, "Linear", "" },
+ { eGPHook_Falloff_Const, "CONSTANT", ICON_NOCURVE, "Constant", "" },
+ { 0, NULL, 0, NULL, NULL }
+};
+
+static const EnumPropertyItem rna_enum_gpencil_lockshift_items[] = {
+ { GP_LOCKAXIS_X, "GP_LOCKAXIS_X", 0, "X", "Use X axis" },
+ { GP_LOCKAXIS_Y, "GP_LOCKAXIS_Y", 0, "Y", "Use Y axis" },
+ { GP_LOCKAXIS_Z, "GP_LOCKAXIS_Z", 0, "Z", "Use Z axis" },
+ { 0, NULL, 0, NULL, NULL }
+};
+
+#endif
+
+#ifdef RNA_RUNTIME
+
+#include "DNA_particle_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_smoke_types.h"
+
+#include "BKE_cachefile.h"
+#include "BKE_context.h"
+#include "BKE_library.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_object.h"
+#include "BKE_gpencil.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr)
+{
+ GpencilModifierData *md = (GpencilModifierData *)ptr->data;
+
+ switch ((GpencilModifierType)md->type) {
+ case eGpencilModifierType_Noise:
+ return &RNA_NoiseGpencilModifier;
+ case eGpencilModifierType_Subdiv:
+ return &RNA_SubdivGpencilModifier;
+ case eGpencilModifierType_Simplify:
+ return &RNA_SimplifyGpencilModifier;
+ case eGpencilModifierType_Thick:
+ return &RNA_ThickGpencilModifier;
+ case eGpencilModifierType_Tint:
+ return &RNA_TintGpencilModifier;
+ case eGpencilModifierType_Color:
+ return &RNA_ColorGpencilModifier;
+ case eGpencilModifierType_Instance:
+ return &RNA_InstanceGpencilModifier;
+ case eGpencilModifierType_Build:
+ return &RNA_BuildGpencilModifier;
+ case eGpencilModifierType_Opacity:
+ return &RNA_OpacityGpencilModifier;
+ case eGpencilModifierType_Lattice:
+ return &RNA_LatticeGpencilModifier;
+ case eGpencilModifierType_Mirror:
+ return &RNA_MirrorGpencilModifier;
+ case eGpencilModifierType_Smooth:
+ return &RNA_SmoothGpencilModifier;
+ case eGpencilModifierType_Hook:
+ return &RNA_HookGpencilModifier;
+ case eGpencilModifierType_Offset:
+ return &RNA_OffsetGpencilModifier;
+ /* Default */
+ case eGpencilModifierType_None:
+ case NUM_GREASEPENCIL_MODIFIER_TYPES:
+ return &RNA_GpencilModifier;
+ }
+
+ return &RNA_GpencilModifier;
+}
+
+static void rna_GpencilModifier_name_set(PointerRNA *ptr, const char *value)
+{
+ GpencilModifierData *gmd = ptr->data;
+ char oldname[sizeof(gmd->name)];
+
+ /* make a copy of the old name first */
+ BLI_strncpy(oldname, gmd->name, sizeof(gmd->name));
+
+ /* copy the new name into the name slot */
+ BLI_strncpy_utf8(gmd->name, value, sizeof(gmd->name));
+
+ /* make sure the name is truly unique */
+ if (ptr->id.data) {
+ Object *ob = ptr->id.data;
+ BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, gmd);
+ }
+
+ /* fix all the animation data which may link to this */
+ BKE_animdata_fix_paths_rename_all(NULL, "grease_pencil_modifiers", oldname, gmd->name);
+}
+
+static char *rna_GpencilModifier_path(PointerRNA *ptr)
+{
+ GpencilModifierData *gmd = ptr->data;
+ char name_esc[sizeof(gmd->name) * 2];
+
+ BLI_strescape(name_esc, gmd->name, sizeof(name_esc));
+ return BLI_sprintfN("grease_pencil_modifiers[\"%s\"]", name_esc);
+}
+
+static void rna_GpencilModifier_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ptr->id.data);
+}
+
+static void rna_GpencilModifier_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ rna_GpencilModifier_update(bmain, scene, ptr);
+ DEG_relations_tag_update(bmain);
+}
+
+/* Vertex Groups */
+
+#define RNA_GP_MOD_VGROUP_NAME_SET(_type, _prop) \
+static void rna_##_type##GpencilModifier_##_prop##_set(PointerRNA *ptr, const char *value) \
+{ \
+ _type##GpencilModifierData *tmd = (_type##GpencilModifierData *)ptr->data; \
+ rna_object_vgroup_name_set(ptr, value, tmd->_prop, sizeof(tmd->_prop)); \
+}
+
+RNA_GP_MOD_VGROUP_NAME_SET(Noise, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Thick, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Opacity, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Lattice, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Smooth, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Hook, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Offset, vgname);
+
+#undef RNA_GP_MOD_VGROUP_NAME_SET
+
+/* Objects */
+
+static void greasepencil_modifier_object_set(Object *self, Object **ob_p, int type, PointerRNA value)
+{
+ Object *ob = value.data;
+
+ if (!self || ob != self) {
+ if (!ob || type == OB_EMPTY || ob->type == type) {
+ id_lib_extern((ID *)ob);
+ *ob_p = ob;
+ }
+ }
+}
+
+#define RNA_GP_MOD_OBJECT_SET(_type, _prop, _obtype) \
+static void rna_##_type##GpencilModifier_##_prop##_set(PointerRNA *ptr, PointerRNA value) \
+{ \
+ _type##GpencilModifierData *tmd = (_type##GpencilModifierData *)ptr->data; \
+ greasepencil_modifier_object_set(ptr->id.data, &tmd->_prop, _obtype, value); \
+}
+
+RNA_GP_MOD_OBJECT_SET(Lattice, object, OB_LATTICE);
+RNA_GP_MOD_OBJECT_SET(Mirror, object, OB_EMPTY);
+
+#undef RNA_GP_MOD_OBJECT_SET
+
+static void rna_HookGpencilModifier_object_set(PointerRNA *ptr, PointerRNA value)
+{
+ HookGpencilModifierData *hmd = ptr->data;
+ Object *ob = (Object *)value.data;
+
+ hmd->object = ob;
+ id_lib_extern((ID *)ob);
+ BKE_object_modifier_gpencil_hook_reset(ob, hmd);
+}
+
+#else
+
+static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "NoiseGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Noise Modifier", "Noise effect modifier");
+ RNA_def_struct_sdna(srna, "NoiseGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_RNDCURVE);
+
+ 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, "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_NoiseGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ 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_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_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "affect_position", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOD_LOCATION);
+ RNA_def_property_ui_text(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, "affect_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, "affect_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, "affect_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");
+ 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);
+ RNA_def_property_ui_text(prop, "Full Stroke", "The noise moves the stroke as a whole, not point by point");
+ 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");
+ 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, "step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "step");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_text(prop, "Step", "Number of frames before recalculate random values again");
+ 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_NOISE_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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_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_NOISE_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilsmooth(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SmoothGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Smooth Modifier", "Smooth effect modifier");
+ RNA_def_struct_sdna(srna, "SmoothGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH);
+
+ 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, "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_SmoothGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "factor");
+ RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_text(prop, "Factor", "Amount of smooth to apply");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "affect_position", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_MOD_LOCATION);
+ RNA_def_property_ui_text(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, "affect_strength", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_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, "affect_thickness", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_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, "affect_uv", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_MOD_UV);
+ RNA_def_property_ui_text(prop, "Affect UV", "The modifier affects the UV rotation factor of the point");
+ 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, "step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "step");
+ RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_ui_text(prop, "Step", "Number of times to apply smooth (high numbers can reduce fps)");
+ 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_SMOOTH_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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_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_SMOOTH_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilsubdiv(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SubdivGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Subdivision Modifier", "Subdivide Stroke modifier");
+ RNA_def_struct_sdna(srna, "SubdivGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_SUBSURF);
+
+ 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, "level", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "level");
+ RNA_def_property_range(prop, 0, 5);
+ 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");
+ 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_SUBDIV_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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SUBDIV_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem prop_gpencil_simplify_mode_items[] = {
+ { GP_SIMPLIFY_FIXED, "FIXED", ICON_IPO_CONSTANT, "Fixed",
+ "Delete alternative vertices in the stroke, except extrems" },
+ { GP_SIMPLIFY_ADAPTATIVE, "ADAPTATIVE", ICON_IPO_EASE_IN_OUT, "Adaptative",
+ "Use a RDP algorithm to simplify" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+ srna = RNA_def_struct(brna, "SimplifyGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Simplify Modifier", "Simplify Stroke modifier");
+ RNA_def_struct_sdna(srna, "SimplifyGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_DECIM);
+
+ 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, "factor", PROP_FLOAT, PROP_NONE);
+ 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);
+ RNA_def_property_ui_text(prop, "Factor", "Factor of Simplify");
+ 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_SIMPLIFY_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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SIMPLIFY_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ /* Mode */
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_gpencil_simplify_mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "How simplify the stroke");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "step");
+ RNA_def_property_range(prop, 1, 50);
+ RNA_def_property_ui_text(prop, "Iterations", "Number of times to apply simplify");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilthick(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ThickGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Thick Modifier", "Subdivide and Smooth Stroke modifier");
+ RNA_def_struct_sdna(srna, "ThickGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MAN_ROT);
+
+ 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, "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_ThickGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ 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_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_THICK_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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_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_THICK_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "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_THICK_CUSTOM_CURVE);
+ RNA_def_property_ui_text(prop, "Custom Curve", "Use a custom curve to define thickness changes");
+ 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_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_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpenciloffset(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "OffsetGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Offset Modifier", "Offset Stroke modifier");
+ RNA_def_struct_sdna(srna, "OffsetGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_DISPLACE);
+
+ 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, "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_OffsetGpencilModifier_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_OFFSET_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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OFFSET_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_OFFSET_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_float_sdna(prop, NULL, "loc");
+ RNA_def_property_ui_text(prop, "Location", "Values for change 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, "rotation", PROP_FLOAT, PROP_EULER);
+ RNA_def_property_float_sdna(prop, NULL, "rot");
+ RNA_def_property_ui_text(prop, "Rotation", "Values for chages 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, "scale", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "scale");
+ RNA_def_property_ui_text(prop, "Scale", "Values 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");
+}
+
+static void rna_def_modifier_gpenciltint(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "TintGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Tint Modifier", "Tint Stroke Color modifier");
+ RNA_def_struct_sdna(srna, "TintGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_COLOR);
+
+ 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, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "rgb");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Color", "Color used for tinting");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ 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 for mixing color");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "create_colors", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_CREATE_COLORS);
+ RNA_def_property_ui_text(prop, "Create Colors", "When apply modifier, create new color in the palette");
+ 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_TINT_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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilcolor(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ColorGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Hue/Saturation Modifier", "Change Hue/Saturation modifier");
+ RNA_def_struct_sdna(srna, "ColorGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_GROUP_VCOL);
+
+ 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, "hue", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 2.0);
+ RNA_def_property_ui_range(prop, 0.0, 2.0, 0.1, 3);
+ 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_ui_range(prop, 0.0, 2.0, 0.1, 3);
+ 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_ui_range(prop, 0.0, 2.0, 0.1, 3);
+ 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_colors", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_COLOR_CREATE_COLORS);
+ RNA_def_property_ui_text(prop, "Create Colors", "When apply modifier, create new color in the palette");
+ 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_COLOR_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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_COLOR_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilopacity(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "OpacityGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Opacity Modifier", "Opacity of Strokes modifier");
+ RNA_def_struct_sdna(srna, "OpacityGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_MASK);
+
+ 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, "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_OpacityGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ 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, "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_OPACITY_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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_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_OPACITY_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilinstance(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "InstanceGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Instance Modifier", "Create grid of duplicate instances");
+ RNA_def_struct_sdna(srna, "InstanceGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_ARRAY);
+
+ 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, "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, "count", PROP_INT, PROP_XYZ);
+ RNA_def_property_range(prop, 1, INT_MAX);
+ RNA_def_property_ui_range(prop, 1, 1000, 1, -1);
+ RNA_def_property_ui_text(prop, "Count", "Number of items");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ /* Offset parameters */
+ prop = RNA_def_property(srna, "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_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);
+ RNA_def_property_float_sdna(prop, NULL, "shift");
+ RNA_def_property_ui_text(prop, "Shift", "Shiftness 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, "lock_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "lock_axis");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_lockshift_items);
+ //RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_ui_text(prop, "Axis", "");
+ 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 chages 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, "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");
+ 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_INSTANCE_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);
+ 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_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_INSTANCE_RANDOM_SIZE);
+ RNA_def_property_ui_text(prop, "Random Scale", "Use random factors for scale");
+ 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);
+ 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_INSTANCE_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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_INSTANCE_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, "use_make_objects", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_INSTANCE_MAKE_OBJECTS);
+ RNA_def_property_ui_text(prop, "Make Objects",
+ "When applying this modifier, instances get created as separate objects");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilbuild(BlenderRNA *brna)
+{
+ static EnumPropertyItem prop_gpencil_build_mode_items[] = {
+ {GP_BUILD_MODE_SEQUENTIAL, "SEQUENTIAL", ICON_PARTICLE_POINT, "Sequential",
+ "Strokes appear/disappear one after the other, but only a single one changes at a time"},
+ {GP_BUILD_MODE_CONCURRENT, "CONCURRENT", ICON_PARTICLE_TIP, "Concurrent",
+ "Multiple strokes appear/disappear at once"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem prop_gpencil_build_transition_items[] = {
+ {GP_BUILD_TRANSITION_GROW, "GROW", 0, "Grow",
+ "Show points in the order they occur in each stroke "
+ "(e.g. for animating lines being drawn)"},
+ {GP_BUILD_TRANSITION_SHRINK, "SHRINK", 0, "Shrink",
+ "Hide points from the end of each stroke to the start "
+ "(e.g. for animating lines being erased)"},
+ {GP_BUILD_TRANSITION_FADE, "FADE", 0, "Fade",
+ "Hide points in the order they occur in each stroke "
+ "(e.g. for animating ink fading or vanishing after getting drawn)"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem prop_gpencil_build_time_align_items[] = {
+ {GP_BUILD_TIMEALIGN_START, "START", 0, "Align Start",
+ "All strokes start at same time (i.e. short strokes finish earlier)"},
+ {GP_BUILD_TIMEALIGN_END, "END", 0, "Align End",
+ "All strokes end at same time (i.e. short strokes start later)"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "BuildGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Build Modifier", "Animate strokes appearing and disappearing");
+ RNA_def_struct_sdna(srna, "BuildGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_BUILD);
+
+ /* Mode */
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_gpencil_build_mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "How many strokes are being animated at a time");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ /* Direction */
+ prop = RNA_def_property(srna, "transition", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_gpencil_build_transition_items);
+ RNA_def_property_ui_text(prop, "Transition", "How are strokes animated (i.e. are they appearing or disappearing)");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+
+ /* Transition Onset Delay + Length */
+ prop = RNA_def_property(srna, "start_delay", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "start_delay");
+ RNA_def_property_ui_text(prop, "Start Delay", "Number of frames after each GP keyframe before the modifier has any effect");
+ RNA_def_property_range(prop, 0, MAXFRAMEF);
+ RNA_def_property_ui_range(prop, 0, 200, 1, -1);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "length");
+ RNA_def_property_ui_text(prop, "Length",
+ "Maximum number of frames that the build effect can run for "
+ "(unless another GP keyframe occurs before this time has elapsed)");
+ RNA_def_property_range(prop, 1, MAXFRAMEF);
+ RNA_def_property_ui_range(prop, 1, 1000, 1, -1);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+
+ /* Concurrent Mode Settings */
+ prop = RNA_def_property(srna, "concurrent_time_alignment", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "time_alignment");
+ RNA_def_property_enum_items(prop, prop_gpencil_build_time_align_items);
+ RNA_def_property_ui_text(prop, "Time Alignment", "When should strokes start to appear/disappear");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+
+
+ /* Time Limits */
+ prop = RNA_def_property(srna, "use_restrict_frame_range", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BUILD_RESTRICT_TIME);
+ RNA_def_property_ui_text(prop, "Restrict Frame Range", "Only modify strokes during the specified frame range");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "start_frame");
+ RNA_def_property_ui_text(prop, "Start Frame", "Start Frame (when Restrict Frame Range is enabled)");
+ RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "end_frame");
+ RNA_def_property_ui_text(prop, "End Frame", "End Frame (when Restrict Frame Range is enabled)");
+ RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+
+ /* Filters - Layer */
+ 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, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BUILD_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ /* Filters - Pass Index */
+#if 0
+ 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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BUILD_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+#endif
+}
+
+static void rna_def_modifier_gpencillattice(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "LatticeGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Lattice Modifier", "Change stroke using lattice to deform modifier");
+ RNA_def_struct_sdna(srna, "LatticeGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_LATTICE);
+
+ 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, "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_LatticeGpencilModifier_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_LATTICE_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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LATTICE_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_LATTICE_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object", "Lattice object to deform with");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_LatticeGpencilModifier_object_set", NULL, "rna_Lattice_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1, 10, 2);
+ RNA_def_property_ui_text(prop, "Strength", "Strength of modifier effect");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilmirror(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "MirrorGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Mirror Modifier", "Change stroke using lattice to deform modifier");
+ RNA_def_struct_sdna(srna, "MirrorGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_MIRROR);
+
+ 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, "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_MIRROR_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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_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, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object", "Object used as center");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_MirrorGpencilModifier_object_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "clip", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_CLIPPING);
+ RNA_def_property_ui_text(prop, "Clip", "Clip points");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "x_axis", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_AXIS_X);
+ RNA_def_property_ui_text(prop, "X", "Mirror this axis");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "y_axis", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_AXIS_Y);
+ RNA_def_property_ui_text(prop, "Y", "Mirror this axis");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "z_axis", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_AXIS_Z);
+ RNA_def_property_ui_text(prop, "Z", "Mirror this axis");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilhook(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "HookGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Hook Modifier", "Hook modifier to modify the location of stroke points");
+ RNA_def_struct_sdna(srna, "HookGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_HOOK);
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object", "Parent Object for hook, also recalculates and clears offset");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_HookGpencilModifier_object_set", NULL, NULL);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "subtarget", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "subtarget");
+ RNA_def_property_ui_text(prop, "Sub-Target",
+ "Name of Parent Bone for hook (if applicable), also recalculates and clears offset");
+ 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, "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_HOOK_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_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_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_HOOK_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "force");
+ RNA_def_property_range(prop, 0, 1);
+ RNA_def_property_ui_text(prop, "Strength", "Relative force of the hook");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "falloff_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, modifier_gphook_falloff_items); /* share the enum */
+ RNA_def_property_ui_text(prop, "Falloff Type", "");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "falloff_radius", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "falloff");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 100, 100, 2);
+ RNA_def_property_ui_text(prop, "Radius", "If not zero, the distance from the hook where influence ends");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curfalloff");
+ RNA_def_property_ui_text(prop, "Falloff Curve", "Custom Lamp Falloff Curve");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "cent");
+ RNA_def_property_ui_text(prop, "Hook Center", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_float_sdna(prop, NULL, "parentinv");
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(prop, "Matrix", "Reverse the transformation between this object and its target");
+ RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_falloff_uniform", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_UNIFORM_SPACE);
+ RNA_def_property_ui_text(prop, "Uniform Falloff", "Compensate for non-uniform object scale");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+void RNA_def_greasepencil_modifier(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ /* data */
+ srna = RNA_def_struct(brna, "GpencilModifier", NULL);
+ RNA_def_struct_ui_text(srna, "GpencilModifier", "Modifier affecting the grease pencil object");
+ RNA_def_struct_refine_func(srna, "rna_GpencilModifier_refine");
+ RNA_def_struct_path_func(srna, "rna_GpencilModifier_path");
+ RNA_def_struct_sdna(srna, "GpencilModifierData");
+
+ /* strings */
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GpencilModifier_name_set");
+ RNA_def_property_ui_text(prop, "Name", "Modifier name");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER | NA_RENAME, NULL);
+ RNA_def_struct_name_property(srna, prop);
+
+ /* enums */
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, rna_enum_object_greasepencil_modifier_type_items);
+ RNA_def_property_ui_text(prop, "Type", "");
+
+ /* flags */
+ prop = RNA_def_property(srna, "show_viewport", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eGpencilModifierMode_Realtime);
+ RNA_def_property_ui_text(prop, "Realtime", "Display modifier in viewport");
+ RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 0);
+
+ prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eGpencilModifierMode_Render);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_text(prop, "Render", "Use modifier during render");
+ RNA_def_property_ui_icon(prop, ICON_SCENE, 0);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "show_in_editmode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eGpencilModifierMode_Editmode);
+ RNA_def_property_ui_text(prop, "Edit Mode", "Display modifier in Edit mode");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ RNA_def_property_ui_icon(prop, ICON_EDITMODE_HLT, 0);
+
+ prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eGpencilModifierMode_Expanded);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_text(prop, "Expanded", "Set modifier expanded in the user interface");
+ RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
+
+ /* types */
+ rna_def_modifier_gpencilnoise(brna);
+ rna_def_modifier_gpencilsmooth(brna);
+ rna_def_modifier_gpencilsubdiv(brna);
+ rna_def_modifier_gpencilsimplify(brna);
+ rna_def_modifier_gpencilthick(brna);
+ rna_def_modifier_gpenciloffset(brna);
+ rna_def_modifier_gpenciltint(brna);
+ rna_def_modifier_gpencilcolor(brna);
+ rna_def_modifier_gpencilinstance(brna);
+ rna_def_modifier_gpencilbuild(brna);
+ rna_def_modifier_gpencilopacity(brna);
+ rna_def_modifier_gpencillattice(brna);
+ rna_def_modifier_gpencilmirror(brna);
+ rna_def_modifier_gpencilhook(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 83d173de6c8..a88623e5b5b 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -153,6 +153,8 @@ void RNA_def_dynamic_paint(struct BlenderRNA *brna);
void RNA_def_fluidsim(struct BlenderRNA *brna);
void RNA_def_fcurve(struct BlenderRNA *brna);
void RNA_def_gpencil(struct BlenderRNA *brna);
+void RNA_def_greasepencil_modifier(struct BlenderRNA *brna);
+void RNA_def_shader_fx(struct BlenderRNA *brna);
void RNA_def_image(struct BlenderRNA *brna);
void RNA_def_key(struct BlenderRNA *brna);
void RNA_def_light(struct BlenderRNA *brna);
@@ -283,6 +285,7 @@ void rna_TextureSlot_update(struct bContext *C, struct PointerRNA *ptr);
bool rna_Armature_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Camera_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Curve_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
+bool rna_GPencil_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Light_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Lattice_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Mesh_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
@@ -291,6 +294,10 @@ bool rna_Mesh_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Action_id_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Action_actedit_assign_poll(struct PointerRNA *ptr, struct PointerRNA value);
+/* Grease Pencil datablock polling functions - for filtering GP Object vs Annotation datablocks */
+bool rna_GPencil_datablocks_annotations_poll(struct PointerRNA *ptr, const struct PointerRNA value);
+bool rna_GPencil_datablocks_obdata_poll(struct PointerRNA *ptr, const struct PointerRNA value);
+
char *rna_TextureSlot_path(struct PointerRNA *ptr);
char *rna_Node_ImageUser_path(struct PointerRNA *ptr);
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index febe74f63c9..50aa3cb5b81 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -231,6 +231,9 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
case ID_LT:
type = OB_LATTICE;
break;
+ case ID_GD:
+ type = OB_GPENCIL;
+ break;
case ID_AR:
type = OB_ARMATURE;
break;
@@ -266,6 +269,11 @@ static Material *rna_Main_materials_new(Main *bmain, const char *name)
return (Material *)id;
}
+static void rna_Main_materials_gpencil_data(Main *UNUSED(bmain), struct PointerRNA *ma)
+{
+ BKE_material_init_gpencil_settings((Material *)ma);
+}
+
static const EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
return rna_node_tree_type_itemf(NULL, NULL, r_free);
@@ -783,6 +791,11 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "create_gpencil_data", "rna_Main_materials_gpencil_data");
+ RNA_def_function_ui_description(func, "Add grease pencil material settings");
+ parm = RNA_def_pointer(func, "material", "Material", "", "Material");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+
func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a material from the current blendfile");
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 0a8ea99b8fb..56f5a12516b 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -72,6 +72,7 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = {
#include "BKE_colorband.h"
#include "BKE_context.h"
#include "BKE_main.h"
+#include "BKE_gpencil.h"
#include "BKE_material.h"
#include "BKE_texture.h"
#include "BKE_node.h"
@@ -85,6 +86,7 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = {
#include "ED_node.h"
#include "ED_image.h"
#include "ED_screen.h"
+#include "ED_gpencil.h"
static void rna_Material_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
@@ -104,6 +106,30 @@ static void rna_Material_update_previews(Main *UNUSED(bmain), Scene *UNUSED(scen
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_PREVIEW, ma);
}
+static void rna_MaterialGpencil_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Material *ma = ptr->id.data;
+ PreviewImage *preview = ma->preview;
+
+ rna_Material_update(bmain, scene, ptr);
+
+ /* update previews (icon and thumbnail) */
+ preview->flag[ICON_SIZE_ICON] |= PRV_CHANGED;
+ preview->flag[ICON_SIZE_PREVIEW] |= PRV_CHANGED;
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING_PREVIEW, ma);
+
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA, ma);
+}
+
+static void rna_MaterialGpencil_nopreview_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Material *ma = ptr->id.data;
+
+ rna_Material_update(bmain, scene, ptr);
+
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA, ma);
+}
+
static void rna_Material_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Material *ma = ptr->id.data;
@@ -243,6 +269,59 @@ void rna_mtex_texture_slots_clear(ID *self_id, struct bContext *C, ReportList *r
WM_event_add_notifier(C, NC_TEXTURE, CTX_data_scene(C));
}
+static bool rna_is_grease_pencil_get(PointerRNA *ptr)
+{
+ Material *ma = (Material *)ptr->data;
+ if (ma->gp_style != NULL)
+ return true;
+
+ return false;
+}
+
+static void rna_gpcolordata_uv_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ /* update all uv strokes of this color */
+ Material *ma = ptr->id.data;
+ ED_gpencil_update_color_uv(bmain, ma);
+
+ rna_MaterialGpencil_update(bmain, scene, ptr);
+}
+
+static char *rna_GpencilColorData_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_sprintfN("grease_pencil");
+}
+
+static int rna_GpencilColorData_is_stroke_visible_get(PointerRNA *ptr)
+{
+ MaterialGPencilStyle *pcolor = ptr->data;
+ return (pcolor->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH);
+}
+
+static int rna_GpencilColorData_is_fill_visible_get(PointerRNA *ptr)
+{
+ MaterialGPencilStyle *pcolor = (MaterialGPencilStyle *)ptr->data;
+ return ((pcolor->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (pcolor->fill_style > 0));
+}
+
+static void rna_GpencilColorData_stroke_image_set(PointerRNA *ptr, PointerRNA value)
+{
+ MaterialGPencilStyle *pcolor = ptr->data;
+ ID *id = value.data;
+
+ id_us_plus(id);
+ pcolor->sima = (struct Image *)id;
+}
+
+static void rna_GpencilColorData_fill_image_set(PointerRNA *ptr, PointerRNA value)
+{
+ MaterialGPencilStyle *pcolor = (MaterialGPencilStyle *)ptr->data;
+ ID *id = value.data;
+
+ id_us_plus(id);
+ pcolor->ima = (struct Image *)id;
+}
+
#else
static void rna_def_material_display(StructRNA *srna)
@@ -296,6 +375,251 @@ static void rna_def_material_display(StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_Material_update");
}
+static void rna_def_material_greasepencil(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ /* 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" },
+ { 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" },
+ { 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_CHESSBOARD, "CHESSBOARD", 0, "Checker Board", "Fill area with chessboard pattern" },
+ { GP_STYLE_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" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+ srna = RNA_def_struct(brna, "MaterialGPencilStyle", NULL);
+ RNA_def_struct_sdna(srna, "MaterialGPencilStyle");
+ 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);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "stroke_rgba");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Color", "");
+ 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);
+ RNA_def_property_float_sdna(prop, NULL, "fill_rgba");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Fill Color", "Color for filling region bounded by each stroke");
+ 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);
+ RNA_def_property_float_sdna(prop, NULL, "mix_rgba");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Mix Color", "Color for mixing with primary filling color");
+ 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);
+ 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_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_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Texture angle */
+ prop = RNA_def_property(srna, "texture_angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "texture_angle");
+ RNA_def_property_ui_text(prop, "Angle", "Texture Orientation Angle");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Scale factor for texture */
+ prop = RNA_def_property(srna, "texture_scale", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_float_sdna(prop, NULL, "texture_scale");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "Scale", "Scale Factor for Texture");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Shift factor to move texture in 2d space */
+ prop = RNA_def_property(srna, "texture_offset", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_float_sdna(prop, NULL, "texture_offset");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "Offset", "Shift Texture in 2d Space");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Texture opacity size */
+ prop = RNA_def_property(srna, "texture_opacity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "texture_opacity");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Opacity", "Texture Opacity");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* texture pixsize factor (used for UV along the stroke) */
+ prop = RNA_def_property(srna, "pixel_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "texture_pixsize");
+ RNA_def_property_range(prop, 1, 5000);
+ RNA_def_property_ui_text(prop, "UV Factor", "Texture Pixel Size factor along the stroke");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_gpcolordata_uv_update");
+
+ /* 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_ui_icon(prop, ICON_RESTRICT_VIEW_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");
+
+ 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_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");
+
+ 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_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");
+
+ 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_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, "texture_mix", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_TEX_MIX);
+ RNA_def_property_ui_text(prop, "Mix Texture", "Mix texture image with filling colors");
+ 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_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");
+
+ /* 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");
+
+ /* mode type */
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, gpcolordata_mode_types_items);
+ RNA_def_property_ui_text(prop, "Mode Type", "Select draw mode for stroke");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* stroke style */
+ prop = RNA_def_property(srna, "stroke_style", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "stroke_style");
+ RNA_def_property_enum_items(prop, stroke_style_items);
+ RNA_def_property_ui_text(prop, "Stroke Style", "Select style used to draw strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* stroke image texture */
+ prop = RNA_def_property(srna, "stroke_image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "sima");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_GpencilColorData_stroke_image_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Image", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* fill style */
+ prop = RNA_def_property(srna, "fill_style", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "fill_style");
+ RNA_def_property_enum_items(prop, fill_style_items);
+ RNA_def_property_ui_text(prop, "Fill Style", "Select style used to fill strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* gradient type */
+ prop = RNA_def_property(srna, "gradient_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "gradient_type");
+ RNA_def_property_enum_items(prop, fill_gradient_items);
+ RNA_def_property_ui_text(prop, "Gradient Type", "Select type of gradient used to fill strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* fill image texture */
+ prop = RNA_def_property(srna, "fill_image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "ima");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_GpencilColorData_fill_image_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Image", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Read-only state props (for simpler UI code) */
+ prop = RNA_def_property(srna, "is_stroke_visible", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_GpencilColorData_is_stroke_visible_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Is Stroke Visible", "True when opacity of stroke is set high enough to be visible");
+
+ prop = RNA_def_property(srna, "is_fill_visible", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_GpencilColorData_is_fill_visible_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Is Fill Visible", "True when opacity of fill is set high enough to be visible");
+
+}
+
void RNA_def_material(BlenderRNA *brna)
{
StructRNA *srna;
@@ -410,6 +734,19 @@ void RNA_def_material(BlenderRNA *brna)
rna_def_material_display(srna);
+ /* grease pencil */
+ prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "gp_style");
+ RNA_def_property_ui_text(prop, "Grease Pencil Settings", "Grease pencil color settings for material");
+
+ prop = RNA_def_property(srna, "is_grease_pencil", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_is_grease_pencil_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Is Grease Pencil", "True if this material has grease pencil data");
+
+ rna_def_material_greasepencil(brna);
+
+
RNA_api_material(srna);
}
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index aded4229a3c..81c3c9b43b9 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -338,6 +338,7 @@ static void rna_def_movieclip(BlenderRNA *brna)
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this movie clip");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index b9a8f306baf..a6172bd9cc2 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -8358,6 +8358,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block");
RNA_def_property_update(prop, NC_NODE, NULL);
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index ac1a6d512c3..d84827210bf 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -37,6 +37,8 @@
#include "DNA_scene_types.h"
#include "DNA_meta_types.h"
#include "DNA_workspace_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_shader_fx_types.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
@@ -71,7 +73,10 @@ const EnumPropertyItem rna_enum_object_mode_items[] = {
{OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""},
{OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""},
{OB_MODE_PARTICLE_EDIT, "PARTICLE_EDIT", ICON_PARTICLEMODE, "Particle Edit", ""},
- {OB_MODE_GPENCIL, "GPENCIL_EDIT", ICON_GREASEPENCIL, "Edit Strokes", "Edit Grease Pencil Strokes"},
+ {OB_MODE_GPENCIL_EDIT, "GPENCIL_EDIT", ICON_EDITMODE_HLT, "Edit Mode", "Edit Grease Pencil Strokes"},
+ {OB_MODE_GPENCIL_SCULPT, "GPENCIL_SCULPT", ICON_SCULPTMODE_HLT, "Sculpt Mode", "Sculpt Grease Pencil Strokes"},
+ {OB_MODE_GPENCIL_PAINT, "GPENCIL_PAINT", ICON_GREASEPENCIL, "Draw", "Paint Grease Pencil Strokes"},
+ {OB_MODE_GPENCIL_WEIGHT, "GPENCIL_WEIGHT", ICON_WPAINT_HLT, "Weight Paint", "Grease Pencil Weight Paint Strokes" },
{0, NULL, 0, NULL, NULL}
};
@@ -87,6 +92,11 @@ const EnumPropertyItem rna_enum_object_empty_drawtype_items[] = {
{0, NULL, 0, NULL, NULL}
};
+const EnumPropertyItem rna_enum_object_gpencil_type_items[] = {
+ { GP_EMPTY, "EMPTY", ICON_OUTLINER_OB_GREASEPENCIL, "Blank", "Create an empty grease pencil object" },
+ { GP_MONKEY, "MONKEY", ICON_MONKEY, "Monkey", "Construct a Suzanne grease pencil object" },
+ { 0, NULL, 0, NULL, NULL }
+};
static const EnumPropertyItem parent_type_items[] = {
{PAROBJECT, "OBJECT", 0, "Object", "The object is parented to an object"},
@@ -144,6 +154,7 @@ const EnumPropertyItem rna_enum_object_type_items[] = {
{OB_ARMATURE, "ARMATURE", 0, "Armature", ""},
{OB_LATTICE, "LATTICE", 0, "Lattice", ""},
{OB_EMPTY, "EMPTY", 0, "Empty", ""},
+ {OB_GPENCIL, "GPENCIL", 0, "GPencil", ""},
{0, "", 0, NULL, NULL},
{OB_CAMERA, "CAMERA", 0, "Camera", ""},
{OB_LAMP, "LIGHT", 0, "Light", ""},
@@ -175,6 +186,7 @@ const EnumPropertyItem rna_enum_object_axis_items[] = {
#include "DNA_key_types.h"
#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_ID.h"
#include "DNA_lattice_types.h"
#include "DNA_node_types.h"
@@ -383,10 +395,24 @@ static StructRNA *rna_Object_data_typef(PointerRNA *ptr)
case OB_ARMATURE: return &RNA_Armature;
case OB_SPEAKER: return &RNA_Speaker;
case OB_LIGHTPROBE: return &RNA_LightProbe;
+ case OB_GPENCIL: return &RNA_GreasePencil;
default: return &RNA_ID;
}
}
+static bool rna_Object_data_poll(PointerRNA *ptr, const PointerRNA value)
+{
+ Object *ob = (Object *)ptr->data;
+
+ if (ob->type == OB_GPENCIL) {
+ /* GP Object - Don't allow using "Annotation" GP datablocks here */
+ bGPdata *gpd = value.data;
+ return (gpd->flag & GP_DATA_ANNOTATIONS) == 0;
+ }
+
+ return true;
+}
+
static void rna_Object_parent_set(PointerRNA *ptr, PointerRNA value)
{
Object *ob = (Object *)ptr->data;
@@ -942,6 +968,21 @@ static void rna_MaterialSlot_material_set(PointerRNA *ptr, PointerRNA value)
assign_material(G_MAIN, ob, value.data, index + 1, BKE_MAT_ASSIGN_EXISTING);
}
+static bool rna_MaterialSlot_material_poll(PointerRNA *ptr, PointerRNA value)
+{
+ Object *ob = (Object *)ptr->id.data;
+ Material *ma = (Material *)value.data;
+
+ if (ob->type == OB_GPENCIL) {
+ /* GP Materials only */
+ return (ma->gp_style != NULL);
+ }
+ else {
+ /* Everything except GP materials */
+ return (ma->gp_style == NULL);
+ }
+}
+
static int rna_MaterialSlot_link_get(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->id.data;
@@ -1007,7 +1048,6 @@ static char *rna_MaterialSlot_path(PointerRNA *ptr)
Object *ob = (Object *)ptr->id.data;
int index = (Material **)ptr->data - ob->mat;
- /* from armature... */
return BLI_sprintfN("material_slots[%d]", index);
}
@@ -1275,6 +1315,61 @@ bool rna_Object_modifiers_override_apply(
return true;
}
+static GpencilModifierData *rna_Object_greasepencil_modifier_new(
+ Object *object, bContext *C, ReportList *reports,
+ const char *name, int type)
+{
+ return ED_object_gpencil_modifier_add(reports, CTX_data_main(C), CTX_data_scene(C), object, name, type);
+}
+
+static void rna_Object_greasepencil_modifier_remove(
+ Object *object, bContext *C, ReportList *reports, PointerRNA *gmd_ptr)
+{
+ GpencilModifierData *gmd = gmd_ptr->data;
+ if (ED_object_gpencil_modifier_remove(reports, CTX_data_main(C), object, gmd) == false) {
+ /* error is already set */
+ return;
+ }
+
+ RNA_POINTER_INVALIDATE(gmd_ptr);
+
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
+}
+
+static void rna_Object_greasepencil_modifier_clear(Object *object, bContext *C)
+{
+ ED_object_gpencil_modifier_clear(CTX_data_main(C), object);
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
+}
+
+/* shader fx */
+static ShaderFxData *rna_Object_shaderfx_new(
+ Object *object, bContext *C, ReportList *reports,
+ const char *name, int type)
+{
+ return ED_object_shaderfx_add(reports, CTX_data_main(C), CTX_data_scene(C), object, name, type);
+}
+
+static void rna_Object_shaderfx_remove(
+ Object *object, bContext *C, ReportList *reports, PointerRNA *gmd_ptr)
+{
+ ShaderFxData *gmd = gmd_ptr->data;
+ if (ED_object_shaderfx_remove(reports, CTX_data_main(C), object, gmd) == false) {
+ /* error is already set */
+ return;
+ }
+
+ RNA_POINTER_INVALIDATE(gmd_ptr);
+
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
+}
+
+static void rna_Object_shaderfx_clear(Object *object, bContext *C)
+{
+ ED_object_shaderfx_clear(CTX_data_main(C), object);
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
+}
+
static void rna_Object_boundbox_get(PointerRNA *ptr, float *values)
{
Object *ob = (Object *)ptr->id.data;
@@ -1453,6 +1548,11 @@ bool rna_Light_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
return ((Object *)value.id.data)->type == OB_LAMP;
}
+bool rna_GPencil_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
+{
+ return ((Object *)value.id.data)->type == OB_GPENCIL;
+}
+
int rna_Object_use_dynamic_topology_sculpting_get(PointerRNA *ptr)
{
SculptSession *ss = ((Object *)ptr->id.data)->sculpt;
@@ -1601,7 +1701,7 @@ static void rna_def_material_slot(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_editable_func(prop, "rna_MaterialSlot_material_editable");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
- RNA_def_property_pointer_funcs(prop, "rna_MaterialSlot_material_get", "rna_MaterialSlot_material_set", NULL, NULL);
+ RNA_def_property_pointer_funcs(prop, "rna_MaterialSlot_material_get", "rna_MaterialSlot_material_set", NULL, "rna_MaterialSlot_material_poll");
RNA_def_property_ui_text(prop, "Material", "Material data-block used by this material slot");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update");
@@ -1715,6 +1815,88 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove all modifiers from the object");
}
+/* object.grease_pencil_modifiers */
+static void rna_def_object_grease_pencil_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "ObjectGpencilModifiers");
+ srna = RNA_def_struct(brna, "ObjectGpencilModifiers", NULL);
+ RNA_def_struct_sdna(srna, "Object");
+ RNA_def_struct_ui_text(srna, "Object Grease Pencil Modifiers", "Collection of object grease pencil modifiers");
+
+ /* add greasepencil modifier */
+ func = RNA_def_function(srna, "new", "rna_Object_greasepencil_modifier_new");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Add a new greasepencil_modifier");
+ parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the greasepencil_modifier");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* greasepencil_modifier to add */
+ parm = RNA_def_enum(func, "type", rna_enum_object_greasepencil_modifier_type_items, 1, "", "Modifier type to add");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "greasepencil_modifier", "GpencilModifier", "", "Newly created modifier");
+ RNA_def_function_return(func, parm);
+
+ /* remove greasepencil_modifier */
+ func = RNA_def_function(srna, "remove", "rna_Object_greasepencil_modifier_remove");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove an existing greasepencil_modifier from the object");
+ /* greasepencil_modifier to remove */
+ parm = RNA_def_pointer(func, "greasepencil_modifier", "GpencilModifier", "", "Modifier to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ /* clear all greasepencil modifiers */
+ func = RNA_def_function(srna, "clear", "rna_Object_greasepencil_modifier_clear");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Remove all grease pencil modifiers from the object");
+}
+
+/* object.shaderfxs */
+static void rna_def_object_shaderfxs(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "ObjectShaderFx");
+ srna = RNA_def_struct(brna, "ObjectShaderFx", NULL);
+ RNA_def_struct_sdna(srna, "Object");
+ RNA_def_struct_ui_text(srna, "Object Shader Effects", "Collection of object effects");
+
+ /* add shader_fx */
+ func = RNA_def_function(srna, "new", "rna_Object_shaderfx_new");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Add a new shader fx");
+ parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the effect");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* shader to add */
+ parm = RNA_def_enum(func, "type", rna_enum_object_shaderfx_type_items, 1, "", "Effect type to add");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "shader_fx", "ShaderFx", "", "Newly created effect");
+ RNA_def_function_return(func, parm);
+
+ /* remove shader_fx */
+ func = RNA_def_function(srna, "remove", "rna_Object_shaderfx_remove");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove an existing effect from the object");
+ /* shader to remove */
+ parm = RNA_def_pointer(func, "shader_fx", "ShaderFx", "", "Effect to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ /* clear all shader fx */
+ func = RNA_def_function(srna, "clear", "rna_Object_shaderfx_clear");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Remove all effects from the object");
+}
+
/* object.particle_systems */
static void rna_def_object_particle_systems(BlenderRNA *brna, PropertyRNA *cprop)
{
@@ -1919,7 +2101,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "ID");
- RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_data_set", "rna_Object_data_typef", NULL);
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_data_set", "rna_Object_data_typef", "rna_Object_data_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Data", "Object data");
@@ -2017,7 +2199,8 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "active_material", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Material");
RNA_def_property_pointer_funcs(prop, "rna_Object_active_material_get",
- "rna_Object_active_material_set", NULL, NULL);
+ "rna_Object_active_material_set", NULL,
+ "rna_MaterialSlot_material_poll");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_func(prop, "rna_Object_active_material_editable");
@@ -2211,6 +2394,20 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_STATIC_INSERTION);
rna_def_object_modifiers(brna, prop);
+ /* Grease Pencil modifiers. */
+ prop = RNA_def_property(srna, "grease_pencil_modifiers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "greasepencil_modifiers", NULL);
+ RNA_def_property_struct_type(prop, "GpencilModifier");
+ RNA_def_property_ui_text(prop, "Grease Pencil Modifiers", "Modifiers affecting the data of the grease pencil object");
+ rna_def_object_grease_pencil_modifiers(brna, prop);
+
+ /* Shader FX. */
+ prop = RNA_def_property(srna, "shader_effects", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "shader_fx", NULL);
+ RNA_def_property_struct_type(prop, "ShaderFx");
+ RNA_def_property_ui_text(prop, "Shader Effects", "Effects affecting display of object");
+ rna_def_object_shaderfxs(brna, prop);
+
/* constraints */
prop = RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Constraint");
@@ -2482,12 +2679,15 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
/* Grease Pencil */
+#if 1 /* FIXME: Remove this code when all Open-Movie assets have been fixed */
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_obdata_poll"); /* XXX */
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
- RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block");
+ RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block (deprecated)");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+#endif
/* pose */
prop = RNA_def_property(srna, "pose_library", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_palette.c b/source/blender/makesrna/intern/rna_palette.c
index 4d6b94bf709..547cac9f38d 100644
--- a/source/blender/makesrna/intern/rna_palette.c
+++ b/source/blender/makesrna/intern/rna_palette.c
@@ -39,7 +39,6 @@
#include "BKE_paint.h"
#include "BKE_report.h"
-
static PaletteColor *rna_Palette_color_new(Palette *palette)
{
PaletteColor *color = BKE_palette_color_add(palette);
@@ -139,6 +138,7 @@ static void rna_def_palettecolor(BlenderRNA *brna)
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "rgb");
+ RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Color", "");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
@@ -153,6 +153,7 @@ static void rna_def_palettecolor(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "value");
RNA_def_property_ui_text(prop, "Weight", "");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
}
static void rna_def_palette(BlenderRNA *brna)
@@ -167,6 +168,7 @@ static void rna_def_palette(BlenderRNA *brna)
prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "PaletteColor");
rna_def_palettecolors(brna, prop);
+
}
void RNA_def_palette(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 915018612a1..9fde87be486 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -51,6 +51,7 @@
#include "BKE_paint.h"
#include "ED_object.h"
+#include "ED_gpencil.h"
#include "GPU_extensions.h"
@@ -530,6 +531,13 @@ static const EnumPropertyItem transform_orientation_items[] = {
#include "FRS_freestyle.h"
#endif
+/* Grease Pencil update cache */
+static void rna_GPencil_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+ DEG_id_type_tag(bmain, ID_GD);
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+}
+
/* Grease Pencil Interpolation settings */
static char *rna_GPencilInterpolateSettings_path(PointerRNA *UNUSED(ptr))
{
@@ -551,110 +559,8 @@ static void rna_GPencilInterpolateSettings_type_set(PointerRNA *ptr, int value)
{
settings->custom_ipo = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
-}
-
-/* Grease pencil Drawing Brushes */
-static bGPDbrush *rna_GPencil_brush_new(ToolSettings *ts, const char *name, bool setactive)
-{
- bGPDbrush *brush = BKE_gpencil_brush_addnew(ts, name, setactive != 0);
-
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return brush;
-}
-
-static void rna_GPencil_brush_remove(ToolSettings *ts, ReportList *reports, PointerRNA *brush_ptr)
-{
- bGPDbrush *brush = brush_ptr->data;
- if (BLI_findindex(&ts->gp_brushes, brush) == -1) {
- BKE_report(reports, RPT_ERROR, "Brush not found in grease pencil data");
- return;
- }
-
- BKE_gpencil_brush_delete(ts, brush);
- RNA_POINTER_INVALIDATE(brush_ptr);
-
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-}
-
-static PointerRNA rna_GPencilBrushes_active_get(PointerRNA *ptr)
-{
- ToolSettings *ts = (ToolSettings *) ptr->data;
-
- bGPDbrush *brush;
-
- for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
- if (brush->flag & GP_BRUSH_ACTIVE) {
- break;
- }
- }
-
- if (brush) {
- return rna_pointer_inherit_refine(ptr, &RNA_GPencilBrush, brush);
- }
-
- return rna_pointer_inherit_refine(ptr, NULL, NULL);
-}
-
-static void rna_GPencilBrushes_active_set(PointerRNA *ptr, PointerRNA value)
-{
- ToolSettings *ts = (ToolSettings *) ptr->data;
-
- bGPDbrush *brush;
-
- for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
- if (brush == value.data) {
- brush->flag |= GP_BRUSH_ACTIVE;
- }
- else {
- brush->flag &= ~GP_BRUSH_ACTIVE;
- }
- }
- WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
-}
-
-static int rna_GPencilBrushes_index_get(PointerRNA *ptr)
-{
- ToolSettings *ts = (ToolSettings *) ptr->data;
- bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
- return BLI_findindex(&ts->gp_brushes, brush);
}
-
-static void rna_GPencilBrushes_index_set(PointerRNA *ptr, int value)
-{
- ToolSettings *ts = (ToolSettings *) ptr->data;
-
- bGPDbrush *brush = BLI_findlink(&ts->gp_brushes, value);
-
- BKE_gpencil_brush_setactive(ts, brush);
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-}
-
-static void rna_GPencilBrushes_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
-{
- ToolSettings *ts = (ToolSettings *) ptr->data;
-
- *min = 0;
- *max = max_ii(0, BLI_listbase_count(&ts->gp_brushes) - 1);
-
- *softmin = *min;
- *softmax = *max;
-}
-
-static void rna_GPencilBrush_name_set(PointerRNA *ptr, const char *value)
-{
- ToolSettings *ts = ((Scene *) ptr->id.data)->toolsettings;
- bGPDbrush *brush = ptr->data;
-
- /* copy the new name into the name slot */
- BLI_strncpy_utf8(brush->info, value, sizeof(brush->info));
-
- BLI_uniquename(&ts->gp_brushes, brush, DATA_("GP_Brush"), '.', offsetof(bGPDbrush, info), sizeof(brush->info));
-}
-
-/* ----------------- end of Grease pencil drawing brushes ------------*/
-
static void rna_ToolSettings_gizmo_flag_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
ToolSettings *ts = scene->toolsettings;
@@ -2190,205 +2096,6 @@ static void rna_def_gpencil_interpolate(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
}
-/* Grease Pencil Drawing Brushes */
-static void rna_def_gpencil_brush(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "GPencilBrush", NULL);
- RNA_def_struct_sdna(srna, "bGPDbrush");
- RNA_def_struct_ui_text(srna, "Grease Pencil Brush",
- "Collection of brushes being used to control the line style of new strokes");
- RNA_def_struct_ui_icon(srna, ICON_BRUSH_DATA);
-
- /* Name */
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "info");
- RNA_def_property_ui_text(prop, "Name", "Brush name");
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilBrush_name_set");
- RNA_def_struct_name_property(srna, prop);
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Line Thickness */
- prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "thickness");
- RNA_def_property_range(prop, 1, 300);
- RNA_def_property_ui_range(prop, 1, 10, 1, 0);
- RNA_def_property_ui_text(prop, "Thickness", "Thickness of strokes (in pixels)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* 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_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Strength factor for new strokes */
- prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_strength");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Strength", "Color strength for new strokes (affect alpha factor of color)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Jitter factor for new strokes */
- prop = RNA_def_property(srna, "jitter", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_jitter");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Jitter", "Jitter factor for new strokes");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Randomnes factor for sensitivity and strength */
- prop = RNA_def_property(srna, "random_press", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_random_press");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Randomness", "Randomness factor for pressure and strength in new strokes");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Randomnes factor for subdivision */
- prop = RNA_def_property(srna, "random_subdiv", PROP_FLOAT, PROP_NONE);
- 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_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");
- RNA_def_property_range(prop, -M_PI_2, M_PI_2);
- RNA_def_property_ui_text(prop, "Angle",
- "Direction of the stroke at which brush gives maximal thickness "
- "(0° for horizontal)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Factor to change brush size depending of angle */
- prop = RNA_def_property(srna, "angle_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_angle_factor");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Angle Factor",
- "Reduce brush thickness by this factor when stroke is perpendicular to 'Angle' direction");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Smoothing factor for new strokes */
- prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac");
- RNA_def_property_range(prop, 0.0, 2.0f);
- RNA_def_property_ui_text(prop, "Smooth",
- "Amount of smoothing to apply to newly created strokes, to reduce jitter/noise");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Iterations of the Smoothing factor */
- prop = RNA_def_property(srna, "pen_smooth_steps", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl");
- RNA_def_property_range(prop, 1, 3);
- RNA_def_property_ui_text(prop, "Iterations",
- "Number of times to smooth newly created strokes");
- 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, "sublevel");
- RNA_def_property_range(prop, 0, 3);
- RNA_def_property_ui_text(prop, "Subdivision Steps",
- "Number of times to subdivide newly created strokes, for less jagged strokes");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Curves for pressure */
- prop = RNA_def_property(srna, "curve_sensitivity", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "cur_sensitivity");
- RNA_def_property_struct_type(prop, "CurveMapping");
- RNA_def_property_ui_text(prop, "Curve Sensitivity", "Curve used for the sensitivity");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "curve_strength", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "cur_strength");
- RNA_def_property_struct_type(prop, "CurveMapping");
- RNA_def_property_ui_text(prop, "Curve Strength", "Curve used for the strength");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "curve_jitter", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "cur_jitter");
- RNA_def_property_struct_type(prop, "CurveMapping");
- RNA_def_property_ui_text(prop, "Curve Jitter", "Curve used for the jitter effect");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Flags */
- prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_PRESSURE);
- RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
- RNA_def_property_ui_text(prop, "Use Pressure", "Use tablet pressure");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "use_strength_pressure", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_STENGTH_PRESSURE);
- RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
- RNA_def_property_ui_text(prop, "Use Pressure Strength", "Use tablet pressure for color strength");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "use_jitter_pressure", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_JITTER_PRESSURE);
- RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
- RNA_def_property_ui_text(prop, "Use Pressure Jitter", "Use tablet pressure for jitter");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "use_random_pressure", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_RANDOM_PRESSURE);
- RNA_def_property_ui_icon(prop, ICON_PARTICLES, 0);
- RNA_def_property_ui_text(prop, "Random Pressure", "Use random value for pressure");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "use_random_strength", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_RANDOM_STRENGTH);
- RNA_def_property_ui_icon(prop, ICON_PARTICLES, 0);
- RNA_def_property_ui_text(prop, "Random Strength", "Use random value for strength");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
-}
-
-/* Grease Pencil Drawing Brushes API */
-static void rna_def_gpencil_brushes(BlenderRNA *brna, PropertyRNA *cprop)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- FunctionRNA *func;
- PropertyRNA *parm;
-
- RNA_def_property_srna(cprop, "GreasePencilBrushes");
- srna = RNA_def_struct(brna, "GreasePencilBrushes", NULL);
- RNA_def_struct_sdna(srna, "ToolSettings");
- RNA_def_struct_ui_text(srna, "Grease Pencil Brushes", "Collection of grease pencil brushes");
-
- func = RNA_def_function(srna, "new", "rna_GPencil_brush_new");
- RNA_def_function_ui_description(func, "Add a new grease pencil brush");
- parm = RNA_def_string(func, "name", "GPencilBrush", MAX_NAME, "Name", "Name of the brush");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- RNA_def_boolean(func, "set_active", 0, "Set Active", "Set the newly created brush to the active brush");
- parm = RNA_def_pointer(func, "palette", "GPencilBrush", "", "The newly created brush");
- RNA_def_function_return(func, parm);
-
- func = RNA_def_function(srna, "remove", "rna_GPencil_brush_remove");
- RNA_def_function_ui_description(func, "Remove a grease pencil brush");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "brush", "GPencilBrush", "", "The brush to remove");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
- RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
-
- prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "GPencilBrush");
- RNA_def_property_pointer_funcs(prop, "rna_GPencilBrushes_active_get", "rna_GPencilBrushes_active_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Active Brush", "Current active brush");
-
- prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop,
- "rna_GPencilBrushes_index_get",
- "rna_GPencilBrushes_index_set",
- "rna_GPencilBrushes_index_range");
- RNA_def_property_ui_text(prop, "Active Brush Index", "Index of active brush");
-}
-
static void rna_def_transform_orientation(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2446,21 +2153,20 @@ static void rna_def_tool_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem gpencil_source_3d_items[] = {
- {GP_TOOL_SOURCE_SCENE, "SCENE", 0, "Scene",
- "Grease Pencil data attached to the current scene is used, "
- "unless the active object already has Grease Pencil data (i.e. for old files)"},
- {GP_TOOL_SOURCE_OBJECT, "OBJECT", 0, "Object",
- "Grease Pencil data-blocks attached to the active object are used "
- "(required when using pre 2.73 add-ons, e.g. BSurfaces)"},
+ static const EnumPropertyItem gpencil_stroke_placement_items[] = {
+ {GP_PROJECT_VIEWSPACE, "ORIGIN", ICON_OBJECT_ORIGIN, "Origin", "Draw stroke at Object origin"},
+ {GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Draw stroke at 3D cursor location" },
+ // {0, "VIEW", ICON_VISIBLE_IPO_ON, "View", "Stick stroke to the view "}, /* weird, GP_PROJECT_VIEWALIGN is inverted */
+ {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_VIEW, "SURFACE", ICON_FACESEL, "Surface", "Stick stroke to surfaces"},
+ //{GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_STROKE, "STROKE", ICON_GREASEPENCIL, "Stroke", "Stick stroke to other strokes"},
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem gpencil_stroke_placement_items[] = {
- {GP_PROJECT_VIEWSPACE, "CURSOR", 0, "Cursor", "Draw stroke at the 3D cursor"},
- {0, "VIEW", 0, "View", "Stick stroke to the view "}, /* weird, GP_PROJECT_VIEWALIGN is inverted */
- {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_VIEW, "SURFACE", 0, "Surface", "Stick stroke to surfaces"},
- {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_STROKE, "STROKE", 0, "Stroke", "Stick stroke to other strokes"},
+ static const EnumPropertyItem annotation_stroke_placement_items[] = {
+ {GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Draw stroke at 3D cursor location" },
+ {0, "VIEW", ICON_VISIBLE_IPO_ON, "View", "Stick stroke to the view "}, /* weird, GP_PROJECT_VIEWALIGN is inverted */
+ {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_VIEW, "SURFACE", ICON_FACESEL, "Surface", "Stick stroke to surfaces"},
+ {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_STROKE, "STROKE", ICON_GREASEPENCIL, "Stroke", "Stick stroke to other strokes"},
{0, NULL, 0, NULL, NULL}
};
@@ -2504,7 +2210,8 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data");
prop = RNA_def_property(srna, "vertex_paint", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "vpaint"); RNA_def_property_ui_text(prop, "Vertex Paint", "");
+ RNA_def_property_pointer_sdna(prop, NULL, "vpaint");
+ RNA_def_property_ui_text(prop, "Vertex Paint", "");
prop = RNA_def_property(srna, "weight_paint", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "wpaint");
@@ -2518,6 +2225,10 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "uvsculpt");
RNA_def_property_ui_text(prop, "UV Sculpt", "");
+ prop = RNA_def_property(srna, "gpencil_paint", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "gp_paint");
+ RNA_def_property_ui_text(prop, "Grease Pencil 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", "");
@@ -2695,12 +2406,6 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ToolSettings_gizmo_flag_update");
/* Grease Pencil */
- prop = RNA_def_property(srna, "use_gpencil_continuous_drawing", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_PAINTSESSIONS_ON);
- RNA_def_property_ui_text(prop, "Use Continuous Drawing",
- "Allow drawing multiple strokes at a time with Grease Pencil");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* xxx: need toolbar to be redrawn... */
-
prop = RNA_def_property(srna, "use_gpencil_additive_drawing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_RETAIN_LAST);
RNA_def_property_ui_text(prop, "Use Additive Drawing",
@@ -2714,12 +2419,11 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"When draw new strokes, the new stroke is drawn below of all strokes in the layer");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "grease_pencil_source", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_src");
- RNA_def_property_enum_items(prop, gpencil_source_3d_items);
- RNA_def_property_ui_text(prop, "Grease Pencil Source",
- "Data-block where active Grease Pencil data is found from");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ prop = RNA_def_property(srna, "use_gpencil_thumbnail_list", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_THUMBNAIL_LIST);
+ RNA_def_property_ui_text(prop, "Compact List",
+ "Show compact list of color instead of thumbnails");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "gpencil_sculpt", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt");
@@ -2733,13 +2437,6 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Grease Pencil Interpolate",
"Settings for Grease Pencil Interpolation tools");
- /* Grease Pencil - Drawing brushes */
- prop = RNA_def_property(srna, "gpencil_brushes", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "gp_brushes", NULL);
- RNA_def_property_struct_type(prop, "GPencilBrush");
- RNA_def_property_ui_text(prop, "Grease Pencil Brushes", "Grease Pencil drawing brushes");
- rna_def_gpencil_brushes(brna, prop);
-
/* Grease Pencil - 3D View Stroke Placement */
prop = RNA_def_property(srna, "gpencil_stroke_placement_view3d", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_v3d_align");
@@ -2752,27 +2449,41 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Only Endpoints", "Only use the first and last parts of the stroke for snapping");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- /* Grease Pencil - 2D Views Stroke Placement */
- prop = RNA_def_property(srna, "gpencil_stroke_placement_view2d", PROP_ENUM, PROP_NONE);
+ /* 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");
- RNA_def_property_enum_items(prop, gpencil_stroke_placement_items);
+ RNA_def_property_enum_items(prop, annotation_stroke_placement_items);
RNA_def_property_ui_text(prop, "Stroke Placement (2D View)", "");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- /* Grease Pencil - Sequencer Preview Stroke Placement */
- prop = RNA_def_property(srna, "gpencil_stroke_placement_sequencer_preview", PROP_ENUM, PROP_NONE);
+ /* Annotations - Sequencer Preview Stroke Placement */
+ prop = RNA_def_property(srna, "annotation_stroke_placement_sequencer_preview", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_seq_align");
- RNA_def_property_enum_items(prop, gpencil_stroke_placement_items);
+ RNA_def_property_enum_items(prop, annotation_stroke_placement_items);
RNA_def_property_ui_text(prop, "Stroke Placement (Sequencer Preview)", "");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- /* Grease Pencil - Image Editor Stroke Placement */
- prop = RNA_def_property(srna, "gpencil_stroke_placement_image_editor", PROP_ENUM, PROP_NONE);
+ /* Annotations - Image Editor Stroke Placement */
+ prop = RNA_def_property(srna, "annotation_stroke_placement_image_editor", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_ima_align");
- RNA_def_property_enum_items(prop, gpencil_stroke_placement_items);
+ RNA_def_property_enum_items(prop, annotation_stroke_placement_items);
RNA_def_property_ui_text(prop, "Stroke Placement (Image Editor)", "");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ /* Annotations - 3D View Stroke Placement */
+ /* XXX: Do we need to decouple the stroke_endpoints setting too? */
+ prop = RNA_def_property(srna, "annotation_stroke_placement_view3d", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "annotate_v3d_align");
+ RNA_def_property_enum_items(prop, annotation_stroke_placement_items);
+ RNA_def_property_ui_text(prop, "Annotation Stroke Placement (3D View)", "How annotation strokes are orientated in 3D space");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Annotations - Stroke Thickness */
+ prop = RNA_def_property(srna, "annotation_thickness", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "annotate_thickness");
+ RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_ui_text(prop, "Annotation Stroke Thickness", "Thickness of annotation strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Auto Keying */
prop = RNA_def_property(srna, "use_keyframe_insert_auto", PROP_BOOLEAN, PROP_NONE);
@@ -5474,6 +5185,32 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Simplify Child Particles", "Global child particles percentage during rendering");
RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
+ /* Grease Pencil - Simplify Options */
+ prop = RNA_def_property(srna, "simplify_gpencil", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_ENABLE);
+ RNA_def_property_ui_text(prop, "Simplify", "Simplify Grease Pencil Drawing");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ 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, "On Play", "Simplify Grease Pencil only when play animation");
+ 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);
+ RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_FILL);
+ RNA_def_property_ui_text(prop, "Fill", "Do not fill strokes on 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_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_REMOVE_FILL_LINE);
+ RNA_def_property_ui_text(prop, "Remove Lines", "Remove External Lines of Filling 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);
+ RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_MODIFIER);
+ RNA_def_property_ui_text(prop, "Fill", "Do not apply modifiers on viewport");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* persistent data */
prop = RNA_def_property(srna, "use_persistent_data", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_PERSISTENT_DATA);
@@ -6550,8 +6287,9 @@ void RNA_def_scene(BlenderRNA *brna)
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
- RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block");
+ RNA_def_property_ui_text(prop, "Annotations", "Grease Pencil data-block used for annotations in the 3D view");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
/* active MovieClip */
@@ -6606,7 +6344,6 @@ void RNA_def_scene(BlenderRNA *brna)
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
rna_def_tool_settings(brna);
- rna_def_gpencil_brush(brna);
rna_def_gpencil_interpolate(brna);
rna_def_unified_paint_settings(brna);
rna_def_curve_paint_settings(brna);
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 5b2a3c9c4f4..6a6c97b41ad 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -64,26 +64,29 @@ static const EnumPropertyItem particle_edit_hair_brush_items[] = {
};
const EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = {
- {GP_EDITBRUSH_TYPE_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth stroke points"},
- {GP_EDITBRUSH_TYPE_THICKNESS, "THICKNESS", 0, "Thickness", "Adjust thickness of strokes"},
- { GP_EDITBRUSH_TYPE_STRENGTH, "STRENGTH", 0, "Strength", "Adjust color strength of strokes" },
- { GP_EDITBRUSH_TYPE_GRAB, "GRAB", 0, "Grab", "Translate the set of points initially within the brush circle" },
- {GP_EDITBRUSH_TYPE_PUSH, "PUSH", 0, "Push", "Move points out of the way, as if combing them"},
- {GP_EDITBRUSH_TYPE_TWIST, "TWIST", 0, "Twist", "Rotate points around the midpoint of the brush"},
- {GP_EDITBRUSH_TYPE_PINCH, "PINCH", 0, "Pinch", "Pull points towards the midpoint of the brush"},
- {GP_EDITBRUSH_TYPE_RANDOMIZE, "RANDOMIZE", 0, "Randomize", "Introduce jitter/randomness into strokes"},
- //{GP_EDITBRUSH_TYPE_SUBDIVIDE, "SUBDIVIDE", 0, "Subdivide", "Increase point density for higher resolution strokes when zoomed in"},
- //{GP_EDITBRUSH_TYPE_SIMPLIFY, "SIMPLIFY", 0, "Simplify", "Reduce density of stroke points"},
- {GP_EDITBRUSH_TYPE_CLONE, "CLONE", 0, "Clone", "Paste copies of the strokes stored on the clipboard"},
+ {GP_EDITBRUSH_TYPE_SMOOTH, "SMOOTH", ICON_GPBRUSH_SMOOTH, "Smooth", "Smooth stroke points"},
+ {GP_EDITBRUSH_TYPE_THICKNESS, "THICKNESS", ICON_GPBRUSH_THICKNESS, "Thickness", "Adjust thickness of strokes"},
+ {GP_EDITBRUSH_TYPE_STRENGTH, "STRENGTH", ICON_GPBRUSH_STRENGTH, "Strength", "Adjust color strength of strokes" },
+ {GP_EDITBRUSH_TYPE_GRAB, "GRAB", ICON_GPBRUSH_GRAB, "Grab", "Translate the set of points initially within the brush circle" },
+ {GP_EDITBRUSH_TYPE_PUSH, "PUSH", ICON_GPBRUSH_PUSH, "Push", "Move points out of the way, as if combing them"},
+ {GP_EDITBRUSH_TYPE_TWIST, "TWIST", ICON_GPBRUSH_TWIST, "Twist", "Rotate points around the midpoint of the brush"},
+ {GP_EDITBRUSH_TYPE_PINCH, "PINCH", ICON_GPBRUSH_PINCH, "Pinch", "Pull points towards the midpoint of the brush"},
+ {GP_EDITBRUSH_TYPE_RANDOMIZE, "RANDOMIZE", ICON_GPBRUSH_RANDOMIZE, "Randomize", "Introduce jitter/randomness into strokes"},
+ {GP_EDITBRUSH_TYPE_CLONE, "CLONE", ICON_GPBRUSH_CLONE, "Clone", "Paste copies of the strokes stored on the clipboard"},
+ { 0, NULL, 0, NULL, NULL }
+};
+
+EnumPropertyItem rna_enum_gpencil_weight_brush_items[] = {
+ { GP_EDITBRUSH_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_lockaxis_items[] = {
- { GP_LOCKAXIS_NONE, "GP_LOCKAXIS_NONE", 0, "None", "" },
- { GP_LOCKAXIS_X, "GP_LOCKAXIS_X", 0, "X", "Project strokes to plane locked to X" },
- { GP_LOCKAXIS_Y, "GP_LOCKAXIS_Y", 0, "Y", "Project strokes to plane locked to Y" },
- { GP_LOCKAXIS_Z, "GP_LOCKAXIS_Z", 0, "Z", "Project strokes to plane locked to Z" },
+ { GP_LOCKAXIS_NONE, "GP_LOCKAXIS_NONE", ICON_UNLOCKED, "None", "" },
+ { GP_LOCKAXIS_X, "GP_LOCKAXIS_X", ICON_NDOF_DOM, "X", "Project strokes to plane locked to X" },
+ { GP_LOCKAXIS_Y, "GP_LOCKAXIS_Y", ICON_NDOF_DOM, "Y", "Project strokes to plane locked to Y" },
+ { GP_LOCKAXIS_Z, "GP_LOCKAXIS_Z", ICON_NDOF_DOM, "Z", "Project strokes to plane locked to Z" },
{ 0, NULL, 0, NULL, NULL }
};
#endif
@@ -108,13 +111,16 @@ const EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
#include "BKE_pbvh.h"
#include "BKE_pointcache.h"
#include "BKE_object.h"
+#include "BKE_gpencil.h"
+
#include "DEG_depsgraph.h"
#include "ED_particle.h"
-static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_GPencil_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
+ DEG_id_type_tag(bmain, ID_GD);
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
@@ -265,6 +271,8 @@ static bool rna_Brush_mode_poll(PointerRNA *ptr, PointerRNA value)
mode = OB_MODE_VERTEX_PAINT;
else if (ptr->data == ts->wpaint)
mode = OB_MODE_WEIGHT_PAINT;
+ else if (ptr->data == ts->gp_paint)
+ mode = OB_MODE_GPENCIL_PAINT;
return brush->ob_mode & mode;
}
@@ -346,6 +354,11 @@ static char *rna_UvSculpt_path(PointerRNA *UNUSED(ptr))
return BLI_strdup("tool_settings.uv_sculpt");
}
+static char *rna_GpPaint_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.gp_paint");
+}
+
static char *rna_ParticleBrush_path(PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.particle_edit.brush");
@@ -435,9 +448,14 @@ static PointerRNA rna_GPencilSculptSettings_brush_get(PointerRNA *ptr)
GP_BrushEdit_Settings *gset = (GP_BrushEdit_Settings *)ptr->data;
GP_EditBrush_Data *brush = NULL;
- if ((gset->brushtype >= 0) && (gset->brushtype < TOT_GP_EDITBRUSH_TYPES))
- brush = &gset->brush[gset->brushtype];
-
+ if ((gset) && (gset->flag & GP_BRUSHEDIT_FLAG_WEIGHT_MODE)) {
+ if ((gset->weighttype >= GP_EDITBRUSH_TYPE_WEIGHT) && (gset->weighttype < TOT_GP_EDITBRUSH_TYPES))
+ brush = &gset->brush[gset->weighttype];
+ }
+ else {
+ if ((gset->brushtype >= 0) && (gset->brushtype < GP_EDITBRUSH_TYPE_WEIGHT))
+ brush = &gset->brush[gset->brushtype];
+ }
return rna_pointer_inherit_refine(ptr, &RNA_GPencilSculptBrush, brush);
}
@@ -708,6 +726,14 @@ static void rna_def_uv_sculpt(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "UV Sculpting", "");
}
+static void rna_def_gp_paint(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ 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 for weight paint too */
static void rna_def_vertex_paint(BlenderRNA *brna)
@@ -1059,8 +1085,8 @@ static void rna_def_particle_edit(BlenderRNA *brna)
static void rna_def_gpencil_sculpt(BlenderRNA *brna)
{
static const EnumPropertyItem prop_direction_items[] = {
- {0, "ADD", 0, "Add", "Add effect of brush"},
- {GP_EDITBRUSH_FLAG_INVERT, "SUBTRACT", 0, "Subtract", "Subtract effect of brush"},
+ {0, "ADD", ICON_ZOOMIN, "Add", "Add effect of brush"},
+ {GP_EDITBRUSH_FLAG_INVERT, "SUBTRACT", ICON_ZOOMOUT, "Subtract", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}};
StructRNA *srna;
@@ -1076,86 +1102,148 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
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_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ 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_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ 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_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_ui_text(prop, "Brush", "");
prop = RNA_def_property(srna, "use_select_mask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_SELECT_MASK);
RNA_def_property_ui_text(prop, "Selection Mask", "Only sculpt selected stroke points");
RNA_def_property_ui_icon(prop, ICON_VERTEXSEL, 0); // FIXME: this needs a custom icon
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "affect_position", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_POSITION);
RNA_def_property_ui_text(prop, "Affect Position", "The brush affects the position of the point");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "affect_strength", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_STRENGTH);
RNA_def_property_ui_text(prop, "Affect Strength", "The brush affects the color strength of the point");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "affect_thickness", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_THICKNESS);
RNA_def_property_ui_text(prop, "Affect Thickness", "The brush affects the thickness of the point");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "affect_uv", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_UV);
+ RNA_def_property_ui_text(prop, "Affect UV", "The brush affects the UV rotation of the point");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "selection_alpha", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "alpha");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Alpha", "Alpha value for selected vertices");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "use_multiframe_falloff", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_FRAME_FALLOFF);
+ RNA_def_property_ui_text(prop, "Use Falloff", "Use falloff effect when edit in multiframe mode to compute brush effect by frame");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ 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");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Curve",
+ "Custom curve to control falloff of brush effect by Grease Pencil frames");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
/* lock axis */
prop = RNA_def_property(srna, "lockaxis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "lock_axis");
RNA_def_property_enum_items(prop, rna_enum_gpencil_lockaxis_items);
RNA_def_property_ui_text(prop, "Lock", "");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* brush */
srna = RNA_def_struct(brna, "GPencilSculptBrush", NULL);
RNA_def_struct_sdna(srna, "GP_EditBrush_Data");
RNA_def_struct_path_func(srna, "rna_GPencilSculptBrush_path");
RNA_def_struct_ui_text(srna, "GPencil Sculpt Brush", "Stroke editing brush");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
- RNA_def_property_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS);
- RNA_def_property_ui_range(prop, 1, 100, 10, 3); // XXX: too big
+ 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_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
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_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
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_EDITBRUSH_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_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
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_EDITBRUSH_FLAG_USE_FALLOFF);
RNA_def_property_ui_text(prop, "Use Falloff", "Strength of brush decays with distance from cursor");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "affect_pressure", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE);
RNA_def_property_ui_text(prop, "Affect Pressure", "Affect pressure values as well when smoothing strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
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_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
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_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ 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 substration");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "use_cursor", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_EDITBRUSH_FLAG_ENABLE_CURSOR);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Enable Cursor", "Enable cursor on screen");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
}
void RNA_def_sculpt_paint(BlenderRNA *brna)
@@ -1166,6 +1254,7 @@ void RNA_def_sculpt_paint(BlenderRNA *brna)
rna_def_paint(brna);
rna_def_sculpt(brna);
rna_def_uv_sculpt(brna);
+ rna_def_gp_paint(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
new file mode 100644
index 00000000000..4956333b202
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_shader_fx.c
@@ -0,0 +1,538 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_shader_fx.c
+ * \ingroup RNA
+ */
+
+
+#include <float.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "DNA_shader_fx_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_animsys.h"
+#include "BKE_shader_fx.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+const EnumPropertyItem rna_enum_object_shaderfx_type_items[] = {
+ {eShaderFxType_Blur, "FX_BLUR", ICON_SOLO_ON, "Blur", "Apply Gaussian Blur to object" },
+ {eShaderFxType_Colorize, "FX_COLORIZE", ICON_SOLO_ON, "Colorize", "Apply different tint effects" },
+ {eShaderFxType_Flip, "FX_FLIP", ICON_SOLO_ON, "Flip", "Flip image" },
+ {eShaderFxType_Light, "FX_LIGHT", ICON_SOLO_ON, "Light", "Simulate ilumination" },
+ {eShaderFxType_Pixel, "FX_PIXEL", ICON_SOLO_ON, "Pixelate", "Pixelate image"},
+ {eShaderFxType_Rim, "FX_RIM", ICON_SOLO_ON, "Rim", "Add a rim to the image" },
+ {eShaderFxType_Swirl, "FX_SWIRL", ICON_SOLO_ON, "Swirl", "Create a rotation distortion"},
+ {eShaderFxType_Wave, "FX_WAVE", ICON_SOLO_ON, "Wave Distortion", "Apply sinusoidal deformation"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+const EnumPropertyItem rna_enum_shaderfx_rim_modes_items[] = {
+ {eShaderFxRimMode_Normal, "NORMAL", 0, "Normal", "" },
+ {eShaderFxRimMode_Overlay, "OVERLAY", 0, "Overlay", "" },
+ {eShaderFxRimMode_Add, "ADD", 0, "Add", "" },
+ {eShaderFxRimMode_Subtract, "SUBTRACT", 0, "Subtract", "" },
+ {eShaderFxRimMode_Multiply, "MULTIPLY", 0, "Multiply", "" },
+ {eShaderFxRimMode_Divide, "DIVIDE", 0, "Divide", "" },
+ {0, NULL, 0, NULL, NULL }
+};
+
+const EnumPropertyItem rna_enum_shaderfx_colorize_modes_items[] = {
+ {eShaderFxColorizeMode_GrayScale, "GRAYSCALE", 0, "Gray Scale", "" },
+ {eShaderFxColorizeMode_Sepia, "SEPIA", 0, "Sepia", "" },
+ {eShaderFxColorizeMode_BiTone, "BITONE", 0, "Bi-Tone", "" },
+ {eShaderFxColorizeMode_Transparent, "TRANSPARENT", 0, "Transparent", "" },
+ {eShaderFxColorizeMode_Custom, "CUSTOM", 0, "Custom", "" },
+ {0, NULL, 0, NULL, NULL }
+};
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_shader_fx.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+static StructRNA *rna_ShaderFx_refine(struct PointerRNA *ptr)
+{
+ ShaderFxData *md = (ShaderFxData *)ptr->data;
+
+ switch ((ShaderFxType)md->type) {
+ case eShaderFxType_Blur:
+ return &RNA_ShaderFxBlur;
+ case eShaderFxType_Colorize:
+ return &RNA_ShaderFxColorize;
+ case eShaderFxType_Wave:
+ return &RNA_ShaderFxWave;
+ case eShaderFxType_Pixel:
+ return &RNA_ShaderFxPixel;
+ case eShaderFxType_Rim:
+ return &RNA_ShaderFxRim;
+ case eShaderFxType_Swirl:
+ return &RNA_ShaderFxSwirl;
+ case eShaderFxType_Flip:
+ return &RNA_ShaderFxFlip;
+ case eShaderFxType_Light:
+ return &RNA_ShaderFxLight;
+ /* Default */
+ case eShaderFxType_None:
+ case NUM_SHADER_FX_TYPES:
+ return &RNA_ShaderFx;
+ }
+
+ return &RNA_ShaderFx;
+}
+
+static void rna_ShaderFx_name_set(PointerRNA *ptr, const char *value)
+{
+ ShaderFxData *gmd = ptr->data;
+ char oldname[sizeof(gmd->name)];
+
+ /* make a copy of the old name first */
+ BLI_strncpy(oldname, gmd->name, sizeof(gmd->name));
+
+ /* copy the new name into the name slot */
+ BLI_strncpy_utf8(gmd->name, value, sizeof(gmd->name));
+
+ /* make sure the name is truly unique */
+ if (ptr->id.data) {
+ Object *ob = ptr->id.data;
+ BKE_shaderfx_unique_name(&ob->shader_fx, gmd);
+ }
+
+ /* fix all the animation data which may link to this */
+ BKE_animdata_fix_paths_rename_all(NULL, "shader_effects", oldname, gmd->name);
+}
+
+static char *rna_ShaderFx_path(PointerRNA *ptr)
+{
+ ShaderFxData *gmd = ptr->data;
+ char name_esc[sizeof(gmd->name) * 2];
+
+ BLI_strescape(name_esc, gmd->name, sizeof(name_esc));
+ return BLI_sprintfN("shader_effects[\"%s\"]", name_esc);
+}
+
+static void rna_ShaderFx_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NC_GPENCIL, ptr->id.data);
+}
+
+static void rna_ShaderFx_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ rna_ShaderFx_update(bmain, scene, ptr);
+ DEG_relations_tag_update(bmain);
+}
+
+/* Objects */
+
+static void shaderfx_object_set(Object *self, Object **ob_p, int type, PointerRNA value)
+{
+ Object *ob = value.data;
+
+ if (!self || ob != self) {
+ if (!ob || type == OB_EMPTY || ob->type == type) {
+ id_lib_extern((ID *)ob);
+ *ob_p = ob;
+ }
+ }
+}
+
+#define RNA_FX_OBJECT_SET(_type, _prop, _obtype) \
+static void rna_##_type##ShaderFx_##_prop##_set(PointerRNA *ptr, PointerRNA value) \
+{ \
+ _type##ShaderFxData *tmd = (_type##ShaderFxData *)ptr->data; \
+ shaderfx_object_set(ptr->id.data, &tmd->_prop, _obtype, value); \
+}
+
+RNA_FX_OBJECT_SET(Light, object, OB_EMPTY);
+RNA_FX_OBJECT_SET(Swirl, object, OB_EMPTY);
+
+#undef RNA_FX_OBJECT_SET
+
+#else
+
+static void rna_def_shader_fx_blur(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxBlur", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Gaussian Blur Effect", "Gaussian Blur effect");
+ RNA_def_struct_sdna(srna, "BlurShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SOLO_ON);
+
+ prop = RNA_def_property(srna, "factor", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "radius");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_ui_text(prop, "Factor", "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);
+ RNA_def_property_int_sdna(prop, NULL, "samples");
+ RNA_def_property_range(prop, 0, 32);
+ RNA_def_property_ui_range(prop, 0, 32, 2, -1);
+ RNA_def_property_int_default(prop, 4);
+ 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");
+ 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_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+}
+
+static void rna_def_shader_fx_colorize(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxColorize", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Colorize Effect", "Colorize effect");
+ RNA_def_struct_sdna(srna, "ColorizeShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SOLO_ON);
+
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "factor");
+ RNA_def_property_range(prop, 0, 1.0);
+ 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);
+ 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);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "high_color");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Hight color", "Second color used for effect");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, rna_enum_shaderfx_colorize_modes_items);
+ RNA_def_property_ui_text(prop, "Mode", "Effect mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+}
+
+static void rna_def_shader_fx_wave(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem prop_shaderfx_wave_type_items[] = {
+ { 0, "HORIZONTAL", 0, "Horizontal", "" },
+ { 1, "VERTICAL", 0, "Vertical", "" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+ srna = RNA_def_struct(brna, "ShaderFxWave", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Wave Deformation Effect", "Wave Deformation effect");
+ RNA_def_struct_sdna(srna, "WaveShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SOLO_ON);
+
+ prop = RNA_def_property(srna, "orientation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "orientation");
+ RNA_def_property_enum_items(prop, prop_shaderfx_wave_type_items);
+ RNA_def_property_ui_text(prop, "Orientation", "Direction of the wave");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "amplitude");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of Wave");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "period", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "period");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Period", "Period of Wave");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "phase", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "phase");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Phase", "Phase Shift of Wave");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+}
+
+static void rna_def_shader_fx_pixel(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxPixel", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Pixelate Effect", "Pixelate effect");
+ RNA_def_struct_sdna(srna, "PixelShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SOLO_ON);
+
+ prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "size");
+ RNA_def_property_range(prop, 1, INT_MAX);
+ RNA_def_property_array(prop, 2);
+ 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);
+ 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)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxRim", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Rim Effect", "Rim effect");
+ RNA_def_struct_sdna(srna, "RimShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SOLO_ON);
+
+ prop = RNA_def_property(srna, "offset", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "offset");
+ RNA_def_property_range(prop, -INT_MAX, INT_MAX);
+ 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);
+ 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);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "mask_rgb");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Mask Color", "Color that must be keept");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, rna_enum_shaderfx_rim_modes_items);
+ RNA_def_property_ui_text(prop, "Mode", "Blend mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "blur", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "blur");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_ui_text(prop, "Blur", "Number of pixels for bluring rim (set to 0 to disable)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "samples");
+ RNA_def_property_range(prop, 0, 32);
+ RNA_def_property_ui_range(prop, 0, 32, 2, -1);
+ RNA_def_property_int_default(prop, 4);
+ 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");
+}
+
+static void rna_def_shader_fx_swirl(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxSwirl", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Swirl Effect", "Swirl effect");
+ RNA_def_struct_sdna(srna, "SwirlShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SOLO_ON);
+
+ prop = RNA_def_property(srna, "radius", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "radius");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_ui_text(prop, "Radius", "Radius to apply");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "angle");
+ RNA_def_property_range(prop, DEG2RAD(-5 * 360), DEG2RAD(5 * 360));
+ RNA_def_property_ui_range(prop, DEG2RAD(-5 * 360), DEG2RAD(5 * 360), 5, 2);
+ RNA_def_property_ui_text(prop, "Angle", "Angle of rotation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "transparent", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_SWIRL_MAKE_TRANSPARENT);
+ RNA_def_property_ui_text(prop, "Transparent", "Make image transparent outside of radius");
+ 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 center location");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_SwirlShaderFx_object_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_ShaderFx_dependency_update");
+}
+
+static void rna_def_shader_fx_flip(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxFlip", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Flip Effect", "Flip effect");
+ RNA_def_struct_sdna(srna, "FlipShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SOLO_ON);
+
+ prop = RNA_def_property(srna, "flip_horizontal", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_FLIP_HORIZONTAL);
+ RNA_def_property_ui_text(prop, "Horizontal", "Flip image horizontally");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "flip_vertical", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_FLIP_VERTICAL);
+ RNA_def_property_ui_text(prop, "Vertical", "Flip image vertically");
+ 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_SOLO_ON);
+
+ 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_update(prop, 0, "rna_ShaderFx_dependency_update");
+}
+
+void RNA_def_shader_fx(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ /* data */
+ srna = RNA_def_struct(brna, "ShaderFx", NULL);
+ RNA_def_struct_ui_text(srna, "ShaderFx", "Effect affecting the grease pencil object");
+ RNA_def_struct_refine_func(srna, "rna_ShaderFx_refine");
+ RNA_def_struct_path_func(srna, "rna_ShaderFx_path");
+ RNA_def_struct_sdna(srna, "ShaderFxData");
+
+ /* strings */
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ShaderFx_name_set");
+ RNA_def_property_ui_text(prop, "Name", "Effect name");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER | NA_RENAME, NULL);
+ RNA_def_struct_name_property(srna, prop);
+
+ /* enums */
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, rna_enum_object_shaderfx_type_items);
+ RNA_def_property_ui_text(prop, "Type", "");
+
+ /* flags */
+ prop = RNA_def_property(srna, "show_viewport", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Realtime);
+ RNA_def_property_ui_text(prop, "Realtime", "Display effect in viewport");
+ RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 0);
+
+ prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Render);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_text(prop, "Render", "Use effect during render");
+ RNA_def_property_ui_icon(prop, ICON_SCENE, 0);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "show_in_editmode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Editmode);
+ RNA_def_property_ui_text(prop, "Edit Mode", "Display effect in Edit mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_ui_icon(prop, ICON_EDITMODE_HLT, 0);
+
+ prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Expanded);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_text(prop, "Expanded", "Set effect expanded in the user interface");
+ RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
+
+ /* types */
+ rna_def_shader_fx_blur(brna);
+ rna_def_shader_fx_colorize(brna);
+ rna_def_shader_fx_wave(brna);
+ rna_def_shader_fx_pixel(brna);
+ rna_def_shader_fx_rim(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 2f009238851..56491fd70e4 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -40,6 +40,7 @@
#include "BLI_math.h"
#include "DNA_action_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
@@ -288,6 +289,7 @@ static const EnumPropertyItem buttons_context_items[] = {
{BCONTEXT_PARTICLE, "PARTICLES", ICON_PARTICLES, "Particles", "Particle"},
{BCONTEXT_PHYSICS, "PHYSICS", ICON_PHYSICS, "Physics", "Physics"},
{BCONTEXT_WORKSPACE, "WORKSPACE", ICON_SPLITSCREEN, "Workspace", "Workspace"},
+ {BCONTEXT_SHADERFX, "SHADERFX", ICON_SOLO_ON, "Effects", "Object visual effects" },
{0, NULL, 0, NULL, NULL}
};
@@ -308,6 +310,14 @@ const EnumPropertyItem rna_enum_file_sort_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static const EnumPropertyItem rna_enum_gpencil_grid_axis_items[] = {
+ {V3D_GP_GRID_AXIS_LOCK, "LOCK", 0, "Lock", "Use current drawing locked axis" },
+ {V3D_GP_GRID_AXIS_X, "X", 0, "X", ""},
+ {V3D_GP_GRID_AXIS_Y, "Y", 0, "Y", ""},
+ {V3D_GP_GRID_AXIS_Z, "Z", 0, "Z", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
#include "DNA_anim_types.h"
@@ -475,6 +485,17 @@ static void rna_Space_view2d_sync_update(Main *UNUSED(bmain), Scene *UNUSED(scen
}
}
+static void rna_GPencil_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+ /* need set all caches as dirty to recalculate onion skinning */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->type == OB_GPENCIL) {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ }
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+}
+
/* Space 3D View */
static void rna_SpaceView3D_camera_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
@@ -1338,6 +1359,10 @@ static const EnumPropertyItem *rna_SpaceProperties_context_itemf(
RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_MODIFIER);
}
+ if (sbuts->pathflag & (1 << BCONTEXT_SHADERFX)) {
+ RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_SHADERFX);
+ }
+
if (sbuts->pathflag & (1 << BCONTEXT_DATA)) {
RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_DATA);
(item + totitem - 1)->icon = sbuts->dataicon;
@@ -2613,7 +2638,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_overlays", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag2", V3D_RENDER_OVERRIDE);
RNA_def_property_ui_text(prop, "Show Overlays", "Display overlays like gizmos and outlines");
- 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, "show_floor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_FLOOR);
@@ -2831,6 +2856,86 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Weight Paint Opacity", "Opacity of the weight paint mode overlay");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* grease pencil paper settings */
+ prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_ANNOTATION);
+ 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, "flag3", V3D_GP_SHOW_PAPER);
+ RNA_def_property_ui_text(prop, "Use Paper",
+ "Cover all viewport with a full color layer to improve visibility while drawing over complex scenes");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_gpencil_grid", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_GP_SHOW_GRID);
+ RNA_def_property_ui_text(prop, "Use Grid",
+ "Draw a grid over grease pencil paper");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "gpencil_grid_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_grid_scale");
+ RNA_def_property_range(prop, 0.01f, FLT_MAX);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Scale", "Grid scale");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "gpencil_grid_lines", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "overlay.gpencil_grid_lines");
+ RNA_def_property_range(prop, 1, INT_MAX);
+ RNA_def_property_int_default(prop, GP_DEFAULT_GRID_LINES);
+ RNA_def_property_ui_text(prop, "Subdivisions", "Number of subdivisions in each side of symmetry line");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "gpencil_grid_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "overlay.gpencil_grid_axis");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_grid_axis_items);
+ RNA_def_property_ui_text(prop, "Axis", "Axis to display grid");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ 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);
+ RNA_def_property_float_default(prop, 0.9f);
+ RNA_def_property_ui_text(prop, "Opacity", "Grid opacity");
+ 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);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_paper_opacity");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Opacity", "Paper opacity");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* show edit lines */
+ prop = RNA_def_property(srna, "use_gpencil_edit_lines", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_GP_SHOW_EDIT_LINES);
+ RNA_def_property_ui_text(prop, "Edit Lines", "Show edit lines when edit 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, "flag3", V3D_GP_SHOW_MULTIEDIT_LINES);
+ RNA_def_property_ui_text(prop, "Lines Only", "Show only edit lines for additional frames");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
+ /* main grease pencil onion switch */
+ prop = RNA_def_property(srna, "use_gpencil_onion_skin", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_GP_SHOW_ONION_SKIN);
+ RNA_def_property_ui_text(prop, "Onion Skins", "Show ghosts of the frames before and after the current frame");
+ 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);
+ 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");
+
}
static void rna_def_space_view3d(BlenderRNA *brna)
@@ -2957,12 +3062,6 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Clip End", "3D View far clipping distance");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_GPENCIL);
- RNA_def_property_ui_text(prop, "Show Grease Pencil",
- "Show grease pencil for this view");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
prop = RNA_def_property(srna, "show_textured_solid", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SOLID_TEX);
RNA_def_property_ui_text(prop, "Textured Solid", "Display face-assigned textures in solid view");
@@ -3143,6 +3242,8 @@ static void rna_def_space_view3d(BlenderRNA *brna)
{"show_object_viewport_lattice", "show_object_select_lattice"}},
{"Empty", (1 << OB_EMPTY),
{"show_object_viewport_empty", "show_object_select_empty"}},
+ {"Grease Pencil", (1 << OB_GPENCIL),
+ {"show_object_viewport_grease_pencil", "show_object_select_grease_pencil"}},
{"Camera", (1 << OB_CAMERA),
{"show_object_viewport_camera", "show_object_select_camera"}},
{"Light", (1 << OB_LAMP),
@@ -3382,10 +3483,10 @@ static void rna_def_space_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Draw Repeated", "Draw the image repeated outside of the main view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
- prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_SHOW_GPENCIL);
- RNA_def_property_ui_text(prop, "Show Grease Pencil",
- "Show grease pencil for this view");
+ RNA_def_property_ui_text(prop, "Show Annotation",
+ "Show annotations for this view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "draw_channels", PROP_ENUM, PROP_NONE);
@@ -3434,6 +3535,7 @@ static void rna_def_space_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this space");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
@@ -3587,10 +3689,10 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
- prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_GPENCIL);
- RNA_def_property_ui_text(prop, "Show Grease Pencil",
- "Show grease pencil for this view");
+ RNA_def_property_ui_text(prop, "Show Annotation",
+ "Show annotations for this view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
prop = RNA_def_property(srna, "display_channel", PROP_INT, PROP_NONE);
@@ -3629,8 +3731,9 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
- RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this space");
+ RNA_def_property_ui_text(prop, "Grease Pencil", "Grease Pencil data for this Preview region");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
prop = RNA_def_property(srna, "overlay_type", PROP_ENUM, PROP_NONE);
@@ -4734,10 +4837,10 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Backdrop", "Use active Viewer Node output as backdrop for compositing nodes");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, "rna_SpaceNodeEditor_show_backdrop_update");
- prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SNODE_SHOW_GPENCIL);
- RNA_def_property_ui_text(prop, "Show Grease Pencil",
- "Show grease pencil for this view");
+ RNA_def_property_ui_text(prop, "Show Annotation",
+ "Show annotations for this view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
prop = RNA_def_property(srna, "use_auto_render", PROP_BOOLEAN, PROP_NONE);
@@ -4802,8 +4905,8 @@ static void rna_def_space_clip(BlenderRNA *brna)
};
static const EnumPropertyItem gpencil_source_items[] = {
- {SC_GPENCIL_SRC_CLIP, "CLIP", 0, "Clip", "Show grease pencil data-block which belongs to movie clip"},
- {SC_GPENCIL_SRC_TRACK, "TRACK", 0, "Track", "Show grease pencil data-block which belongs to active track"},
+ {SC_GPENCIL_SRC_CLIP, "CLIP", 0, "Clip", "Show annotation data-block which belongs to movie clip"},
+ {SC_GPENCIL_SRC_TRACK, "TRACK", 0, "Track", "Show annotation data-block which belongs to active track"},
{0, NULL, 0, NULL, NULL}
};
@@ -4953,11 +5056,11 @@ static void rna_def_space_clip(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Manual Calibration", "Use manual calibration helpers");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
- /* show grease pencil */
- prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SC_SHOW_GPENCIL);
- RNA_def_property_ui_text(prop, "Show Grease Pencil",
- "Show grease pencil for this view");
+ /* show annotation */
+ prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SC_SHOW_ANNOTATION);
+ RNA_def_property_ui_text(prop, "Show Annotation",
+ "Show annotations for this view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
/* show filters */
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index 5da49ac5957..4c5af755b13 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -1480,6 +1480,7 @@ static void rna_def_trackingTrack(BlenderRNA *brna)
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this track");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index c9ce9ae7961..a5deb0a32f1 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -759,6 +759,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink the ID block");
RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL,
"", "Optionally limit the items which can be selected");
+ RNA_def_boolean(func, "live_icon", false, "", "Show preview instead of fixed icon");
func = RNA_def_function(srna, "template_ID_preview", "uiTemplateIDPreview");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -831,6 +832,31 @@ void RNA_api_ui_layout(StructRNA *srna)
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "template_greasepencil_modifier", "uiTemplateGpencilModifier");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Generates the UI layout for grease pencil modifiers");
+ parm = RNA_def_pointer(func, "data", "GpencilModifier", "", "Modifier data");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "template_shaderfx", "uiTemplateShaderFx");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Generates the UI layout for shader effect");
+ parm = RNA_def_pointer(func, "data", "ShaderFx", "", "Shader data");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "template_greasepencil_color", "uiTemplateGpencilColorPreview");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
+ RNA_def_int(func, "rows", 0, 0, INT_MAX, "Number of thumbnail preview rows to display", "", 0, INT_MAX);
+ RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX);
+ RNA_def_float(func, "scale", 1.0f, 0.1f, 1.5f, "Scale of the image thumbnails", "", 0.5f, 1.0f);
+ RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL,
+ "", "Optionally limit the items which can be selected");
+
func = RNA_def_function(srna, "template_constraint", "uiTemplateConstraint");
RNA_def_function_ui_description(func, "Generates the UI layout for constraints");
parm = RNA_def_pointer(func, "data", "Constraint", "", "Constraint data");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 3c92b6c143b..4c3074bba4f 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -4371,6 +4371,14 @@ static void rna_def_userdef_system(BlenderRNA *brna)
"Enable OpenGL multi-sampling, only for systems that support it, 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(prop, "Region Overlap",
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index 5c3f510ffca..0b27cadd086 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -739,6 +739,9 @@ int RE_engine_render(Render *re, int do_all)
type->render(engine, engine->depsgraph);
+ /* grease pencil render over previous render result */
+ DRW_render_gpencil(engine, engine->depsgraph);
+
engine_depsgraph_free(engine);
}
FOREACH_VIEW_LAYER_TO_RENDER_END;
diff --git a/source/blender/shader_fx/CMakeLists.txt b/source/blender/shader_fx/CMakeLists.txt
new file mode 100644
index 00000000000..2b33c9817c3
--- /dev/null
+++ b/source/blender/shader_fx/CMakeLists.txt
@@ -0,0 +1,64 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# 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) 2018, Blender Foundation
+# All rights reserved.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ intern
+ ../blenkernel
+ ../blenlib
+ ../blenfont
+ ../depsgraph
+ ../makesdna
+ ../makesrna
+ ../bmesh
+ ../render/extern/include
+ ../../../intern/elbeem/extern
+ ../../../intern/guardedalloc
+ ../../../intern/eigen
+)
+
+set(INC_SYS
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+set(SRC
+ intern/FX_shader_util.h
+
+ intern/FX_shader_util.c
+ intern/FX_shader_blur.c
+ intern/FX_shader_colorize.c
+ intern/FX_shader_flip.c
+ intern/FX_shader_light.c
+ intern/FX_shader_pixel.c
+ intern/FX_shader_rim.c
+ intern/FX_shader_swirl.c
+ intern/FX_shader_wave.c
+
+ FX_shader_types.h
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+add_definitions(${GL_DEFINITIONS})
+
+blender_add_lib(bf_shader_fx "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/shader_fx/FX_shader_types.h b/source/blender/shader_fx/FX_shader_types.h
new file mode 100644
index 00000000000..b8d8f04e07f
--- /dev/null
+++ b/source/blender/shader_fx/FX_shader_types.h
@@ -0,0 +1,47 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * Contributor(s): Ben Batt
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file FX_shader_types.h
+ * \ingroup shader_fx
+ */
+
+#ifndef __FX_SHADER_TYPES_H__
+#define __FX_SHADER_TYPES_H__
+
+#include "BKE_shader_fx.h"
+
+/* ****************** Type structures for all effects ****************** */
+
+extern ShaderFxTypeInfo shaderfx_Type_None;
+extern ShaderFxTypeInfo shaderfx_Type_Blur;
+extern ShaderFxTypeInfo shaderfx_Type_Colorize;
+extern ShaderFxTypeInfo shaderfx_Type_Flip;
+extern ShaderFxTypeInfo shaderfx_Type_Light;
+extern ShaderFxTypeInfo shaderfx_Type_Pixel;
+extern ShaderFxTypeInfo shaderfx_Type_Rim;
+extern ShaderFxTypeInfo shaderfx_Type_Swirl;
+extern ShaderFxTypeInfo shaderfx_Type_Wave;
+
+/* FX_shaderfx_util.c */
+void shaderfx_type_init(ShaderFxTypeInfo *types[]);
+
+#endif /* __FX_SHADER_TYPES_H__ */
diff --git a/source/blender/shader_fx/intern/FX_shader_blur.c b/source/blender/shader_fx/intern/FX_shader_blur.c
new file mode 100644
index 00000000000..128ebba8875
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_blur.c
@@ -0,0 +1,66 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_blur.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "BLI_utildefines.h"
+
+#include "FX_shader_types.h"
+
+static void initData(ShaderFxData *fx)
+{
+ BlurShaderFxData *gpfx = (BlurShaderFxData *)fx;
+ ARRAY_SET_ITEMS(gpfx->radius, 1, 1);
+ gpfx->samples = 4;
+ gpfx->coc = 0.025f;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Blur = {
+ /* name */ "Blur",
+ /* structName */ "BlurShaderFxData",
+ /* structSize */ sizeof(BlurShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ eShaderFxTypeFlag_Single,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_colorize.c b/source/blender/shader_fx/intern/FX_shader_colorize.c
new file mode 100644
index 00000000000..edf276b842c
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_colorize.c
@@ -0,0 +1,69 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_colorize.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_shader_fx_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "FX_shader_types.h"
+
+static void initData(ShaderFxData *fx)
+{
+ ColorizeShaderFxData *gpfx = (ColorizeShaderFxData *)fx;
+ ARRAY_SET_ITEMS(gpfx->low_color, 0.0f, 0.0f, 0.0f, 1.0f);
+ ARRAY_SET_ITEMS(gpfx->high_color, 1.0f, 1.0f, 1.0f, 1.0f);
+ gpfx->mode = eShaderFxColorizeMode_GrayScale;
+ gpfx->factor = 0.5f;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Colorize = {
+ /* name */ "Colorize",
+ /* structName */ "ColorizeShaderFxData",
+ /* structSize */ sizeof(ColorizeShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_flip.c b/source/blender/shader_fx/intern/FX_shader_flip.c
new file mode 100644
index 00000000000..404e2f8160e
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_flip.c
@@ -0,0 +1,69 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_flip.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BLI_math_base.h"
+#include "BLI_utildefines.h"
+
+#include "FX_shader_types.h"
+
+static void initData(ShaderFxData *fx)
+{
+ FlipShaderFxData *gpfx = (FlipShaderFxData *)fx;
+ gpfx->flag |= FX_FLIP_HORIZONTAL;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Flip = {
+ /* name */ "Flip",
+ /* structName */ "FlipShaderFxData",
+ /* structSize */ sizeof(FlipShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ eShaderFxTypeFlag_Single,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_light.c b/source/blender/shader_fx/intern/FX_shader_light.c
new file mode 100644
index 00000000000..9a17ea8ae5f
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_light.c
@@ -0,0 +1,104 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_light.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BLI_math_base.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_library_query.h"
+#include "BKE_modifier.h"
+#include "BKE_shader_fx.h"
+
+#include "FX_shader_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+static void initData(ShaderFxData *fx)
+{
+ LightShaderFxData *gpfx = (LightShaderFxData *)fx;
+ gpfx->energy = 10.0f;
+ gpfx->ambient = 5.0f;
+ gpfx->object = NULL;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+static void updateDepsgraph(ShaderFxData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ LightShaderFxData *fxd = (LightShaderFxData *)md;
+ if (fxd->object != NULL) {
+ DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_GEOMETRY, "Light ShaderFx");
+ DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_TRANSFORM, "Light ShaderFx");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Light ShaderFx");
+}
+
+static bool isDisabled(ShaderFxData *fx, int UNUSED(userRenderParams))
+{
+ LightShaderFxData *fxd = (LightShaderFxData *)fx;
+
+ return !fxd->object;
+}
+
+static void foreachObjectLink(
+ ShaderFxData *fx, Object *ob,
+ ShaderFxObjectWalkFunc walk, void *userData)
+{
+ LightShaderFxData *fxd = (LightShaderFxData *)fx;
+
+ walk(userData, ob, &fxd->object, IDWALK_CB_NOP);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Light = {
+ /* name */ "Light",
+ /* structName */ "LightShaderFxData",
+ /* structSize */ sizeof(LightShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_pixel.c b/source/blender/shader_fx/intern/FX_shader_pixel.c
new file mode 100644
index 00000000000..a3ffd3a9b0d
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_pixel.c
@@ -0,0 +1,66 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_pixel.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "BLI_utildefines.h"
+
+#include "FX_shader_types.h"
+
+static void initData(ShaderFxData *fx)
+{
+ PixelShaderFxData *gpfx = (PixelShaderFxData *)fx;
+ ARRAY_SET_ITEMS(gpfx->size, 5, 5);
+ ARRAY_SET_ITEMS(gpfx->rgba, 0.0f, 0.0f, 0.0f, 0.9f);
+ gpfx->flag |= FX_PIXEL_USE_LINES;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Pixel = {
+ /* name */ "Pixelate",
+ /* structName */ "PixelShaderFxData",
+ /* structSize */ sizeof(PixelShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ eShaderFxTypeFlag_Single,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_rim.c b/source/blender/shader_fx/intern/FX_shader_rim.c
new file mode 100644
index 00000000000..611e6f91bf7
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_rim.c
@@ -0,0 +1,70 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_rim.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_shader_fx_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "FX_shader_types.h"
+
+static void initData(ShaderFxData *fx)
+{
+ RimShaderFxData *gpfx = (RimShaderFxData *)fx;
+ ARRAY_SET_ITEMS(gpfx->offset, 50, -100);
+ ARRAY_SET_ITEMS(gpfx->rim_rgb, 1.0f, 1.0f, 0.5f, 0.9f);
+ ARRAY_SET_ITEMS(gpfx->mask_rgb, 0.0f, 0.0f, 0.0f, 1.0f);
+ gpfx->mode = eShaderFxRimMode_Multiply;
+ ARRAY_SET_ITEMS(gpfx->blur, 0, 0);
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Rim = {
+ /* name */ "Rim",
+ /* structName */ "RimShaderFxData",
+ /* structSize */ sizeof(RimShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_swirl.c b/source/blender/shader_fx/intern/FX_shader_swirl.c
new file mode 100644
index 00000000000..9667f466eec
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_swirl.c
@@ -0,0 +1,103 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_swirl.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BLI_math_base.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_library_query.h"
+#include "BKE_modifier.h"
+#include "BKE_shader_fx.h"
+
+#include "FX_shader_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+static void initData(ShaderFxData *md)
+{
+ SwirlShaderFxData *gpmd = (SwirlShaderFxData *)md;
+ gpmd->radius = 100;
+ gpmd->angle = M_PI_2;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+static void updateDepsgraph(ShaderFxData *fx, const ModifierUpdateDepsgraphContext *ctx)
+{
+ SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
+ if (fxd->object != NULL) {
+ DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_GEOMETRY, "Swirl ShaderFx");
+ DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_TRANSFORM, "Swirl ShaderFx");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Swirl ShaderFx");
+}
+
+static bool isDisabled(ShaderFxData *fx, int UNUSED(userRenderParams))
+{
+ SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
+
+ return !fxd->object;
+}
+
+static void foreachObjectLink(
+ ShaderFxData *fx, Object *ob,
+ ShaderFxObjectWalkFunc walk, void *userData)
+{
+ SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
+
+ walk(userData, ob, &fxd->object, IDWALK_CB_NOP);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Swirl = {
+ /* name */ "Swirl",
+ /* structName */ "SwirlShaderFxData",
+ /* structSize */ sizeof(SwirlShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_util.c b/source/blender/shader_fx/intern/FX_shader_util.c
new file mode 100644
index 00000000000..c55b9304503
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_util.c
@@ -0,0 +1,56 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_util.c
+ * \ingroup shader_fx
+ */
+
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_shader_fx.h"
+
+#include "FX_shader_types.h"
+#include "FX_shader_util.h"
+
+void shaderfx_type_init(ShaderFxTypeInfo *types[])
+{
+#define INIT_FX_TYPE(typeName) (types[eShaderFxType_##typeName] = &shaderfx_Type_##typeName)
+ INIT_FX_TYPE(Blur);
+ INIT_FX_TYPE(Colorize);
+ INIT_FX_TYPE(Flip);
+ INIT_FX_TYPE(Light);
+ INIT_FX_TYPE(Pixel);
+ INIT_FX_TYPE(Rim);
+ INIT_FX_TYPE(Swirl);
+ INIT_FX_TYPE(Wave);
+#undef INIT_FX_TYPE
+}
+
diff --git a/source/blender/shader_fx/intern/FX_shader_util.h b/source/blender/shader_fx/intern/FX_shader_util.h
new file mode 100644
index 00000000000..e2fdcd6fb4c
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_util.h
@@ -0,0 +1,36 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_util.h
+ * \ingroup shader_fx
+ */
+
+
+#ifndef __FX_SHADER_UTIL_H__
+#define __FX_SHADER_UTIL_H__
+
+#endif /* __FX_SHADER_UTIL_H__ */
diff --git a/source/blender/shader_fx/intern/FX_shader_wave.c b/source/blender/shader_fx/intern/FX_shader_wave.c
new file mode 100644
index 00000000000..ea4563a00e1
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_wave.c
@@ -0,0 +1,71 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_wave.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "FX_shader_types.h"
+
+static void initData(ShaderFxData *fx)
+{
+ WaveShaderFxData *gpfx = (WaveShaderFxData *)fx;
+ gpfx->amplitude = 10.0f;
+ gpfx->period = 20.0f;
+ gpfx->phase = 0.0f;
+ gpfx->orientation = 1;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Wave = {
+ /* name */ "Wave Distorsion",
+ /* structName */ "WaveShaderFxData",
+ /* structSize */ sizeof(WaveShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ eShaderFxTypeFlag_Single,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index df869ba6b68..76a1482ac7c 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -440,7 +440,7 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr
switch (GS(((ID *)ptr->id.data)->name)) {
case ID_SCE:
{
- CTX_TEST_PTR_DATA_TYPE(C, "active_gpencil_brush", RNA_GPencilBrush, ptr, CTX_data_active_gpencil_brush(C));
+ CTX_TEST_PTR_DATA_TYPE(C, "active_gpencil_brush", RNA_Brush, ptr, CTX_data_active_gpencil_brush(C));
CTX_TEST_PTR_ID(C, "scene", ptr->id.data);
break;
}
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 18396149342..914211afd56 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -63,7 +63,9 @@
#include "BKE_global.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_node.h"
+#include "BKE_shader_fx.h"
#include "BKE_sound.h"
#include "BKE_image.h"
#include "BKE_particle.h"
@@ -371,6 +373,8 @@ int main(
BKE_cachefiles_init();
BKE_images_init();
BKE_modifier_init();
+ BKE_gpencil_modifier_init();
+ BKE_shaderfx_init();
DEG_register_node_types();
BKE_brush_system_init();