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
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
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.
-rw-r--r--build_files/cmake/macros.cmake5
-rw-r--r--intern/cycles/blender/addon/ui.py5
-rw-r--r--release/datafiles/brushicons/gp_brush_block.pngbin0 -> 6088 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_clone.pngbin0 -> 2586 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_erase_hard.pngbin0 -> 6107 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_erase_soft.pngbin0 -> 6252 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_erase_stroke.pngbin0 -> 5955 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_fill.pngbin0 -> 5707 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_grab.pngbin0 -> 2741 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_ink.pngbin0 -> 4034 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_inknoise.pngbin0 -> 5591 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_marker.pngbin0 -> 5996 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_pen.pngbin0 -> 4920 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_pencil.pngbin0 -> 3965 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_pinch.pngbin0 -> 5432 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_push.pngbin0 -> 2914 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_randomize.pngbin0 -> 5726 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_smooth.pngbin0 -> 3105 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_strength.pngbin0 -> 3229 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_thickness.pngbin0 -> 5066 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_twist.pngbin0 -> 4776 bytes
-rw-r--r--release/datafiles/brushicons/gp_brush_weight.pngbin0 -> 2460 bytes
-rw-r--r--release/datafiles/icons/brush.gpencil.draw.eraser_hard.datbin0 -> 1736 bytes
-rw-r--r--release/datafiles/icons/brush.gpencil.draw.eraser_soft.datbin0 -> 1880 bytes
-rw-r--r--release/datafiles/icons/brush.gpencil.draw.eraser_stroke.datbin0 -> 2456 bytes
-rw-r--r--release/datafiles/icons/brush.gpencil.draw_block.datbin0 -> 2006 bytes
-rw-r--r--release/datafiles/icons/brush.gpencil.draw_fill.datbin0 -> 6326 bytes
-rw-r--r--release/datafiles/icons/brush.gpencil.draw_ink.datbin0 -> 2240 bytes
-rw-r--r--release/datafiles/icons/brush.gpencil.draw_marker.datbin0 -> 2690 bytes
-rw-r--r--release/datafiles/icons/brush.gpencil.draw_noise.datbin0 -> 3086 bytes
-rw-r--r--release/datafiles/icons/brush.gpencil.draw_pen.datbin0 -> 3158 bytes
-rw-r--r--release/datafiles/icons/brush.gpencil.draw_pencil.datbin0 -> 2780 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.draw.datbin0 -> 2492 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.draw.eraser.datbin0 -> 2384 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.draw.line.datbin0 -> 1664 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.draw.poly.datbin0 -> 1736 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.edit_bend.datbin0 -> 2330 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.edit_mirror.datbin0 -> 620 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.edit_shear.datbin0 -> 332 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.edit_to_sphere.datbin0 -> 1790 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.sculpt_clone.datbin0 -> 4328 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.sculpt_grab.datbin0 -> 1664 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.sculpt_pinch.datbin0 -> 3482 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.sculpt_push.datbin0 -> 1664 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.sculpt_randomize.datbin0 -> 6254 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.sculpt_smooth.datbin0 -> 3788 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.sculpt_strength.datbin0 -> 5228 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.sculpt_thickness.datbin0 -> 1700 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.sculpt_twist.datbin0 -> 2942 bytes
-rw-r--r--release/datafiles/icons/ops.gpencil.sculpt_weight.datbin0 -> 1736 bytes
-rw-r--r--release/datafiles/preview_grease_pencil.blendbin0 -> 947876 bytes
-rw-r--r--release/datafiles/userdef/userdef_default_theme.c10
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/modules/bpy_extras/keyconfig_utils.py6
-rw-r--r--release/scripts/startup/bl_operators/presets.py37
-rw-r--r--release/scripts/startup/bl_ui/__init__.py3
-rw-r--r--release/scripts/startup/bl_ui/properties_data_gpencil.py402
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py445
-rw-r--r--release/scripts/startup/bl_ui/properties_data_shaderfx.py134
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py785
-rw-r--r--release/scripts/startup/bl_ui/properties_material.py7
-rw-r--r--release/scripts/startup/bl_ui/properties_material_gpencil.py322
-rw-r--r--release/scripts/startup/bl_ui/properties_scene.py35
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py45
-rw-r--r--release/scripts/startup/bl_ui/space_image.py55
-rw-r--r--release/scripts/startup/bl_ui/space_node.py56
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py10
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py564
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py11
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py11
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py324
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py415
-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
322 files changed, 39488 insertions, 6437 deletions
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index ae265654724..65f962d2dd9 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -598,12 +598,12 @@ function(SETUP_BLENDER_SORTED_LIBS)
bf_editor_util
bf_editor_uvedit
bf_editor_curve
- bf_editor_gpencil
bf_editor_interface
bf_editor_gizmo_library
bf_editor_mesh
bf_editor_metaball
bf_editor_object
+ bf_editor_gpencil
bf_editor_lattice
bf_editor_armature
bf_editor_physics
@@ -626,12 +626,15 @@ function(SETUP_BLENDER_SORTED_LIBS)
bf_freestyle
bf_ikplugin
bf_modifiers
+ bf_gpencil_modifiers
bf_alembic
bf_bmesh
bf_gpu
bf_draw
bf_blenloader
bf_blenkernel
+ bf_shader_fx
+ bf_gpencil_modifiers
bf_physics
bf_nodes
bf_rna
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index a1941ce6176..737f7416486 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -895,7 +895,10 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel):
@classmethod
def poll(cls, context):
- return (context.material or context.object) and CyclesButtonsPanel.poll(context)
+ if context.active_object and context.active_object.type == 'GPENCIL':
+ return False
+ else:
+ return (context.material or context.object) and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
diff --git a/release/datafiles/brushicons/gp_brush_block.png b/release/datafiles/brushicons/gp_brush_block.png
new file mode 100644
index 00000000000..2db3964e573
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_block.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_clone.png b/release/datafiles/brushicons/gp_brush_clone.png
new file mode 100644
index 00000000000..8358ace23b3
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_clone.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_erase_hard.png b/release/datafiles/brushicons/gp_brush_erase_hard.png
new file mode 100644
index 00000000000..2ac52840678
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_erase_hard.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_erase_soft.png b/release/datafiles/brushicons/gp_brush_erase_soft.png
new file mode 100644
index 00000000000..416923004dd
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_erase_soft.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_erase_stroke.png b/release/datafiles/brushicons/gp_brush_erase_stroke.png
new file mode 100644
index 00000000000..cd6d21532cf
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_erase_stroke.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_fill.png b/release/datafiles/brushicons/gp_brush_fill.png
new file mode 100644
index 00000000000..9dac633139c
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_fill.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_grab.png b/release/datafiles/brushicons/gp_brush_grab.png
new file mode 100644
index 00000000000..2123ac69aef
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_grab.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_ink.png b/release/datafiles/brushicons/gp_brush_ink.png
new file mode 100644
index 00000000000..410a77f6117
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_ink.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_inknoise.png b/release/datafiles/brushicons/gp_brush_inknoise.png
new file mode 100644
index 00000000000..5356f697e01
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_inknoise.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_marker.png b/release/datafiles/brushicons/gp_brush_marker.png
new file mode 100644
index 00000000000..c7a62b78ca7
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_marker.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_pen.png b/release/datafiles/brushicons/gp_brush_pen.png
new file mode 100644
index 00000000000..9aaaa861f49
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_pen.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_pencil.png b/release/datafiles/brushicons/gp_brush_pencil.png
new file mode 100644
index 00000000000..2d1fbdfd916
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_pencil.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_pinch.png b/release/datafiles/brushicons/gp_brush_pinch.png
new file mode 100644
index 00000000000..e38236d1be0
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_pinch.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_push.png b/release/datafiles/brushicons/gp_brush_push.png
new file mode 100644
index 00000000000..542764309cc
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_push.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_randomize.png b/release/datafiles/brushicons/gp_brush_randomize.png
new file mode 100644
index 00000000000..0dd1a131d86
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_randomize.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_smooth.png b/release/datafiles/brushicons/gp_brush_smooth.png
new file mode 100644
index 00000000000..7518a358219
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_smooth.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_strength.png b/release/datafiles/brushicons/gp_brush_strength.png
new file mode 100644
index 00000000000..a0513119f29
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_strength.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_thickness.png b/release/datafiles/brushicons/gp_brush_thickness.png
new file mode 100644
index 00000000000..6026716f026
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_thickness.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_twist.png b/release/datafiles/brushicons/gp_brush_twist.png
new file mode 100644
index 00000000000..84b9a90e9d6
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_twist.png
Binary files differ
diff --git a/release/datafiles/brushicons/gp_brush_weight.png b/release/datafiles/brushicons/gp_brush_weight.png
new file mode 100644
index 00000000000..171e9221e92
--- /dev/null
+++ b/release/datafiles/brushicons/gp_brush_weight.png
Binary files differ
diff --git a/release/datafiles/icons/brush.gpencil.draw.eraser_hard.dat b/release/datafiles/icons/brush.gpencil.draw.eraser_hard.dat
new file mode 100644
index 00000000000..1e909ca8ac9
--- /dev/null
+++ b/release/datafiles/icons/brush.gpencil.draw.eraser_hard.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.gpencil.draw.eraser_soft.dat b/release/datafiles/icons/brush.gpencil.draw.eraser_soft.dat
new file mode 100644
index 00000000000..7242f76a0f9
--- /dev/null
+++ b/release/datafiles/icons/brush.gpencil.draw.eraser_soft.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.gpencil.draw.eraser_stroke.dat b/release/datafiles/icons/brush.gpencil.draw.eraser_stroke.dat
new file mode 100644
index 00000000000..6bf620bf3c2
--- /dev/null
+++ b/release/datafiles/icons/brush.gpencil.draw.eraser_stroke.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.gpencil.draw_block.dat b/release/datafiles/icons/brush.gpencil.draw_block.dat
new file mode 100644
index 00000000000..7a7402ef673
--- /dev/null
+++ b/release/datafiles/icons/brush.gpencil.draw_block.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.gpencil.draw_fill.dat b/release/datafiles/icons/brush.gpencil.draw_fill.dat
new file mode 100644
index 00000000000..809aed7f3cf
--- /dev/null
+++ b/release/datafiles/icons/brush.gpencil.draw_fill.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.gpencil.draw_ink.dat b/release/datafiles/icons/brush.gpencil.draw_ink.dat
new file mode 100644
index 00000000000..3c654712783
--- /dev/null
+++ b/release/datafiles/icons/brush.gpencil.draw_ink.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.gpencil.draw_marker.dat b/release/datafiles/icons/brush.gpencil.draw_marker.dat
new file mode 100644
index 00000000000..77a52dd83d4
--- /dev/null
+++ b/release/datafiles/icons/brush.gpencil.draw_marker.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.gpencil.draw_noise.dat b/release/datafiles/icons/brush.gpencil.draw_noise.dat
new file mode 100644
index 00000000000..127f469b9fb
--- /dev/null
+++ b/release/datafiles/icons/brush.gpencil.draw_noise.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.gpencil.draw_pen.dat b/release/datafiles/icons/brush.gpencil.draw_pen.dat
new file mode 100644
index 00000000000..cb6fb77924a
--- /dev/null
+++ b/release/datafiles/icons/brush.gpencil.draw_pen.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.gpencil.draw_pencil.dat b/release/datafiles/icons/brush.gpencil.draw_pencil.dat
new file mode 100644
index 00000000000..a8898a94917
--- /dev/null
+++ b/release/datafiles/icons/brush.gpencil.draw_pencil.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.draw.dat b/release/datafiles/icons/ops.gpencil.draw.dat
new file mode 100644
index 00000000000..3adc50ab17d
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.draw.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.draw.eraser.dat b/release/datafiles/icons/ops.gpencil.draw.eraser.dat
new file mode 100644
index 00000000000..323d8c23245
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.draw.eraser.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.draw.line.dat b/release/datafiles/icons/ops.gpencil.draw.line.dat
new file mode 100644
index 00000000000..238db63807a
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.draw.line.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.draw.poly.dat b/release/datafiles/icons/ops.gpencil.draw.poly.dat
new file mode 100644
index 00000000000..8351e48fec1
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.draw.poly.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.edit_bend.dat b/release/datafiles/icons/ops.gpencil.edit_bend.dat
new file mode 100644
index 00000000000..32f7b2e9631
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.edit_bend.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.edit_mirror.dat b/release/datafiles/icons/ops.gpencil.edit_mirror.dat
new file mode 100644
index 00000000000..ee073664f78
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.edit_mirror.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.edit_shear.dat b/release/datafiles/icons/ops.gpencil.edit_shear.dat
new file mode 100644
index 00000000000..e6b51f988f8
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.edit_shear.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.edit_to_sphere.dat b/release/datafiles/icons/ops.gpencil.edit_to_sphere.dat
new file mode 100644
index 00000000000..bf1181cd500
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.edit_to_sphere.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.sculpt_clone.dat b/release/datafiles/icons/ops.gpencil.sculpt_clone.dat
new file mode 100644
index 00000000000..dbae6a68159
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.sculpt_clone.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.sculpt_grab.dat b/release/datafiles/icons/ops.gpencil.sculpt_grab.dat
new file mode 100644
index 00000000000..291b4fd12dc
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.sculpt_grab.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.sculpt_pinch.dat b/release/datafiles/icons/ops.gpencil.sculpt_pinch.dat
new file mode 100644
index 00000000000..cb2b43f5597
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.sculpt_pinch.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.sculpt_push.dat b/release/datafiles/icons/ops.gpencil.sculpt_push.dat
new file mode 100644
index 00000000000..e1c4961ff86
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.sculpt_push.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.sculpt_randomize.dat b/release/datafiles/icons/ops.gpencil.sculpt_randomize.dat
new file mode 100644
index 00000000000..35042936757
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.sculpt_randomize.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.sculpt_smooth.dat b/release/datafiles/icons/ops.gpencil.sculpt_smooth.dat
new file mode 100644
index 00000000000..3a132ed4049
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.sculpt_smooth.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.sculpt_strength.dat b/release/datafiles/icons/ops.gpencil.sculpt_strength.dat
new file mode 100644
index 00000000000..7e52b0d7648
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.sculpt_strength.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.sculpt_thickness.dat b/release/datafiles/icons/ops.gpencil.sculpt_thickness.dat
new file mode 100644
index 00000000000..1e558806888
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.sculpt_thickness.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.sculpt_twist.dat b/release/datafiles/icons/ops.gpencil.sculpt_twist.dat
new file mode 100644
index 00000000000..4ce958cb7ec
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.sculpt_twist.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.gpencil.sculpt_weight.dat b/release/datafiles/icons/ops.gpencil.sculpt_weight.dat
new file mode 100644
index 00000000000..41b58abfda7
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.sculpt_weight.dat
Binary files differ
diff --git a/release/datafiles/preview_grease_pencil.blend b/release/datafiles/preview_grease_pencil.blend
new file mode 100644
index 00000000000..82661d80029
--- /dev/null
+++ b/release/datafiles/preview_grease_pencil.blend
Binary files differ
diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c
index 11a9fbaca00..69ad58ea1c5 100644
--- a/release/datafiles/userdef/userdef_default_theme.c
+++ b/release/datafiles/userdef/userdef_default_theme.c
@@ -1,8 +1,8 @@
/*
- * Generated by 'source/tools/utils/blender_theme_as_c.py'
- *
- * Do not hand edit this file!
- */
+* Generated by 'source/tools/utils/blender_theme_as_c.py'
+*
+* Do not hand edit this file!
+*/
#include "DNA_userdef_types.h"
@@ -1040,5 +1040,5 @@ const bTheme U_theme_default = {
.select = RGBA(0x000000ff),
.active = RGBA(0x000000ff),
},
- },
+},
};
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject c87ee4d46f16d60a2e1db7514c8d5ab42c5d93d
+Subproject 371960484a38fc64e0a2635170a41a0d8ab2f6b
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject 15b25a42783d1e516b5298d70b582fae2559ae1
+Subproject 474702157831f1a58bb50f5240ab8b1b02b6ba3
diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py
index 6859e327b66..4e5cb7daad9 100644
--- a/release/scripts/modules/bpy_extras/keyconfig_utils.py
+++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py
@@ -121,6 +121,12 @@ KM_HIERARCHY = [
('Grease Pencil', 'EMPTY', 'WINDOW', [ # grease pencil stuff (per region)
('Grease Pencil Stroke Edit Mode', 'EMPTY', 'WINDOW', []),
+ ('Grease Pencil Stroke Paint (Draw brush)', 'EMPTY', 'WINDOW', []),
+ ('Grease Pencil Stroke Paint (Fill)', 'EMPTY', 'WINDOW', []),
+ ('Grease Pencil Stroke Paint (Erase)', 'EMPTY', 'WINDOW', []),
+ ('Grease Pencil Stroke Paint Mode', 'EMPTY', 'WINDOW', []),
+ ('Grease Pencil Stroke Sculpt Mode', 'EMPTY', 'WINDOW', []),
+ ('Grease Pencil Stroke Weight Mode', 'EMPTY', 'WINDOW', []),
]),
('Mask Editing', 'EMPTY', 'WINDOW', []),
('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region)
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index fe09fada297..0fe45f8fee3 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -670,6 +670,42 @@ class AddPresetUnitsLength(AddPresetBase, Operator):
preset_subdir = "units_length"
+class AddPresetGpencilBrush(AddPresetBase, Operator):
+ """Add or remove grease pencil brush preset"""
+ bl_idname = "scene.gpencil_brush_preset_add"
+ bl_label = "Add Grease Pencil Brush Preset"
+ preset_menu = "VIEW3D_PT_gpencil_brush_presets"
+
+ preset_defines = [
+ "brush = bpy.context.active_gpencil_brush",
+ "settings = brush.gpencil_settings"
+ ]
+
+ preset_values = [
+ "settings.input_samples",
+ "settings.active_smooth_factor",
+ "settings.angle",
+ "settings.angle_factor",
+ "settings.use_stabilizer",
+ "brush.smooth_stroke_radius",
+ "brush.smooth_stroke_factor",
+ "settings.pen_smooth_factor",
+ "settings.pen_smooth_steps",
+ "settings.pen_thick_smooth_factor",
+ "settings.pen_thick_smooth_steps",
+ "settings.pen_subdivision_steps",
+ "settings.random_subdiv",
+ "settings.enable_random",
+ "settings.random_pressure",
+ "settings.random_strength",
+ "settings.uv_random",
+ "settings.pen_jitter",
+ "settings.use_jitter_pressure",
+ ]
+
+ preset_subdir = "gpencil_brush"
+
+
classes = (
AddPresetCamera,
AddPresetCloth,
@@ -686,6 +722,7 @@ classes = (
AddPresetTrackingSettings,
AddPresetTrackingTrackColor,
AddPresetUnitsLength,
+ AddPresetGpencilBrush,
ExecutePreset,
WM_MT_operator_presets,
)
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index 51ba45cdcd7..89aed37f055 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -34,16 +34,19 @@ _modules = [
"properties_data_camera",
"properties_data_curve",
"properties_data_empty",
+ "properties_data_gpencil",
"properties_data_light",
"properties_data_lattice",
"properties_data_mesh",
"properties_data_metaball",
"properties_data_modifier",
+ "properties_data_shaderfx",
"properties_data_lightprobe",
"properties_data_speaker",
"properties_data_workspace",
"properties_mask_common",
"properties_material",
+ "properties_material_gpencil",
"properties_object",
"properties_paint_common",
"properties_grease_pencil_common",
diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py
new file mode 100644
index 00000000000..14407afa8f2
--- /dev/null
+++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py
@@ -0,0 +1,402 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+import bpy
+from bpy.types import Menu, Panel, UIList
+from rna_prop_ui import PropertyPanel
+from .properties_grease_pencil_common import (
+ GreasePencilDataPanel,
+ GreasePencilOnionPanel,
+ )
+
+###############################
+# Base-Classes (for shared stuff - e.g. poll, attributes, etc.)
+
+class DataButtonsPanel:
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+
+ @classmethod
+ def poll(cls, context):
+ return context.object and context.object.type == 'GPENCIL'
+
+
+class LayerDataButtonsPanel:
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+
+ @classmethod
+ def poll(cls, context):
+ return (context.object and
+ context.object.type == 'GPENCIL' and
+ context.active_gpencil_layer)
+
+
+###############################
+# GP Object Properties Panels and Helper Classes
+
+class DATA_PT_gpencil(DataButtonsPanel, Panel):
+ bl_label = ""
+ bl_options = {'HIDE_HEADER'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ # Grease Pencil data selector
+ gpd_owner = context.gpencil_data_owner
+ gpd = context.gpencil_data
+
+ layout.template_ID(gpd_owner, "data")
+
+
+class GPENCIL_UL_layer(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ # assert(isinstance(item, bpy.types.GPencilLayer)
+ gpl = item
+ gpd = context.gpencil_data
+
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ if gpl.lock:
+ layout.active = False
+
+ row = layout.row(align=True)
+ if gpl.is_parented:
+ icon = 'BONE_DATA'
+ else:
+ icon = 'BLANK1'
+
+ row.label(text="", icon=icon)
+ row.prop(gpl, "info", text="", emboss=False)
+
+ row = layout.row(align=True)
+ row.prop(gpl, "lock", text="", emboss=False)
+ row.prop(gpl, "hide", text="", emboss=False)
+ row.prop(gpl, "unlock_color", text="", emboss=False)
+ if gpl.use_onion_skinning is False:
+ icon = 'GHOST_DISABLED'
+ else:
+ icon = 'GHOST_ENABLED'
+ subrow = row.row(align=True)
+ subrow.prop(gpl, "use_onion_skinning", text="", icon=icon, emboss=False)
+ subrow.active = gpd.use_onion_skinning
+ elif self.layout_type == 'GRID':
+ layout.alignment = 'CENTER'
+ layout.label(text="", icon_value=icon)
+
+
+class GPENCIL_MT_layer_specials(Menu):
+ bl_label = "Layer"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("gpencil.layer_duplicate", icon='COPY_ID') # XXX: needs a dedicated icon
+
+ layout.separator()
+
+ layout.operator("gpencil.reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
+ layout.operator("gpencil.hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True
+
+ layout.separator()
+
+ layout.operator("gpencil.lock_all", icon='LOCKED', text="Lock All")
+ layout.operator("gpencil.unlock_all", icon='UNLOCKED', text="UnLock All")
+
+ layout.separator()
+
+ layout.operator("gpencil.layer_merge", icon='NLA', text="Merge Down")
+
+
+class DATA_PT_gpencil_datapanel(Panel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+ bl_label = "Layers"
+
+ @classmethod
+ def poll(cls, context):
+ if context.gpencil_data is None:
+ return False
+
+ ob = context.object
+ if ob is not None and ob.type == 'GPENCIL':
+ return True
+
+ return False
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ #layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ gpd = context.gpencil_data
+
+ # Grease Pencil data...
+ if (gpd is None) or (not gpd.layers):
+ layout.operator("gpencil.layer_add", text="New Layer")
+ else:
+ self.draw_layers(context, layout, gpd)
+
+ def draw_layers(self, context, layout, gpd):
+ row = layout.row()
+
+ col = row.column()
+ if len(gpd.layers) >= 2:
+ layer_rows = 5
+ else:
+ layer_rows = 2
+ col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index", rows=layer_rows)
+
+ col = row.column()
+
+ sub = col.column(align=True)
+ sub.operator("gpencil.layer_add", icon='ZOOMIN', text="")
+ sub.operator("gpencil.layer_remove", icon='ZOOMOUT', text="")
+
+ gpl = context.active_gpencil_layer
+ if gpl:
+ sub.menu("GPENCIL_MT_layer_specials", icon='DOWNARROW_HLT', text="")
+
+ if len(gpd.layers) > 1:
+ col.separator()
+
+ sub = col.column(align=True)
+ sub.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
+ sub.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
+
+ col.separator()
+
+ sub = col.column(align=True)
+ sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
+ sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True
+
+ row = layout.row(align=True)
+ if gpl:
+ row.prop(gpl, "opacity", text="Opacity", slider=True)
+
+
+class DATA_PT_gpencil_layer_optionpanel(LayerDataButtonsPanel, Panel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+ bl_label = "Adjustments"
+ bl_parent_id = 'DATA_PT_gpencil_datapanel'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ gpl = context.active_gpencil_layer
+ layout.active = not gpl.lock
+
+ # Layer options
+ # Offsets - Color Tint
+ layout.enabled = not gpl.lock
+ col = layout.column(align=True)
+ col.prop(gpl, "tint_color")
+ col.prop(gpl, "tint_factor", slider=True)
+
+ # Offsets - Thickness
+ col = layout.row(align=True)
+ col.prop(gpl, "line_change", text="Stroke Thickness")
+
+
+class DATA_PT_gpencil_parentpanel(LayerDataButtonsPanel, Panel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+ bl_label = "Relations"
+ bl_parent_id = 'DATA_PT_gpencil_datapanel'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ gpl = context.active_gpencil_layer
+ col = layout.column(align=True)
+ col.active = not gpl.lock
+ col.prop(gpl, "parent", text="Parent")
+ col.prop(gpl, "parent_type", text="Parent Type")
+ parent = gpl.parent
+
+ if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE':
+ col.prop_search(gpl, "parent_bone", parent.data, "bones", text="Bone")
+
+
+class DATA_PT_gpencil_onionpanel(Panel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+ bl_label = "Onion Skinning"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return bool(context.active_gpencil_layer)
+
+ @staticmethod
+ def draw_header(self, context):
+ self.layout.prop(context.gpencil_data, "use_onion_skinning", text="")
+
+ def draw(self, context):
+ gpd = context.gpencil_data
+
+ layout = self.layout
+ layout.use_property_split = True
+ layout.enabled = gpd.use_onion_skinning
+
+ GreasePencilOnionPanel.draw_settings(layout, gpd)
+
+
+class GPENCIL_MT_gpencil_vertex_group(Menu):
+ bl_label = "GP Vertex Groups"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator_context = 'EXEC_AREA'
+ layout.operator("object.vertex_group_add")
+
+ ob = context.active_object
+ if ob.vertex_groups.active:
+ layout.separator()
+
+ layout.operator("gpencil.vertex_group_assign", text="Assign to Active Group")
+ layout.operator("gpencil.vertex_group_remove_from", text="Remove from Active Group")
+
+ layout.separator()
+ layout.operator_menu_enum("object.vertex_group_set_active", "group", text="Set Active Group")
+ layout.operator("object.vertex_group_remove", text="Remove Active Group").all = False
+ layout.operator("object.vertex_group_remove", text="Remove All Groups").all = True
+
+ layout.separator()
+ layout.operator("gpencil.vertex_group_select", text="Select Points")
+ layout.operator("gpencil.vertex_group_deselect", text="Deselect Points")
+
+
+class GPENCIL_UL_vgroups(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ vgroup = item
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ layout.prop(vgroup, "name", text="", emboss=False, icon_value=icon)
+ # icon = 'LOCKED' if vgroup.lock_weight else 'UNLOCKED'
+ # layout.prop(vgroup, "lock_weight", text="", icon=icon, emboss=False)
+ elif self.layout_type == 'GRID':
+ layout.alignment = 'CENTER'
+ layout.label(text="", icon_value=icon)
+
+
+class DATA_PT_gpencil_vertexpanel(DataButtonsPanel, Panel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+ bl_label = "Vertex Groups"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ ob = context.object
+ group = ob.vertex_groups.active
+
+ rows = 2
+ if group:
+ rows = 4
+
+ row = layout.row()
+ row.template_list("GPENCIL_UL_vgroups", "", ob, "vertex_groups", ob.vertex_groups, "active_index", rows=rows)
+
+ col = row.column(align=True)
+ col.operator("object.vertex_group_add", icon='ZOOMIN', text="")
+ col.operator("object.vertex_group_remove", icon='ZOOMOUT', text="").all = False
+
+ if ob.vertex_groups:
+ row = layout.row()
+
+ sub = row.row(align=True)
+ sub.operator("gpencil.vertex_group_assign", text="Assign")
+ sub.operator("gpencil.vertex_group_remove_from", text="Remove")
+
+ sub = row.row(align=True)
+ sub.operator("gpencil.vertex_group_select", text="Select")
+ sub.operator("gpencil.vertex_group_deselect", text="Deselect")
+
+ layout.prop(context.tool_settings, "vertex_group_weight", text="Weight")
+
+
+class DATA_PT_gpencil_display(DataButtonsPanel, Panel):
+ bl_label = "Viewport Display"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ ob = context.object
+
+ gpd = context.gpencil_data
+ gpl = context.active_gpencil_layer
+
+ layout.prop(gpd, "xray_mode", text="Depth Ordering")
+ layout.prop(gpd, "edit_line_color", text="Edit Line Color")
+ layout.prop(ob, "empty_draw_size", text="Marker Size")
+
+ col = layout.column(align=True)
+ col.prop(gpd, "show_constant_thickness")
+ sub = col.column()
+ sub.active = not gpd.show_constant_thickness
+ sub.prop(gpd, "pixfactor", text="Thickness Scale")
+
+ if gpl:
+ layout.prop(gpd, "show_stroke_direction", text="Show Stroke Directions")
+
+
+class DATA_PT_custom_props_gpencil(DataButtonsPanel, PropertyPanel, Panel):
+ _context_path = "object.data"
+ _property_type = bpy.types.GreasePencil
+
+###############################
+
+classes = (
+ DATA_PT_gpencil,
+ DATA_PT_gpencil_datapanel,
+ DATA_PT_gpencil_onionpanel,
+ DATA_PT_gpencil_layer_optionpanel,
+ DATA_PT_gpencil_parentpanel,
+ DATA_PT_gpencil_vertexpanel,
+ DATA_PT_gpencil_display,
+ DATA_PT_custom_props_gpencil,
+
+ GPENCIL_UL_layer,
+ GPENCIL_UL_vgroups,
+
+ GPENCIL_MT_layer_specials,
+ GPENCIL_MT_gpencil_vertex_group,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index 03ebea69d2b..2328925bbad 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -28,10 +28,14 @@ class ModifierButtonsPanel:
bl_context = "modifier"
bl_options = {'HIDE_HEADER'}
-
class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
bl_label = "Modifiers"
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return ob and ob.type != 'GPENCIL'
+
def draw(self, context):
layout = self.layout
@@ -1563,8 +1567,447 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
layout.operator("object.correctivesmooth_bind", text="Unbind" if is_bind else "Bind")
+class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
+ bl_label = "Modifiers"
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return ob and ob.type == 'GPENCIL'
+
+ def draw(self, context):
+ layout = self.layout
+
+ ob = context.object
+
+ layout.operator_menu_enum("object.gpencil_modifier_add", "type")
+
+ for md in ob.grease_pencil_modifiers:
+ box = layout.template_greasepencil_modifier(md)
+ if box:
+ # match enum type to our functions, avoids a lookup table.
+ getattr(self, md.type)(box, ob, md)
+
+ # the mt.type enum is (ab)used for a lookup on function names
+ # ...to avoid lengthy if statements
+ # so each type must have a function here.
+
+ def GP_NOISE(self, layout, ob, md):
+ gpd = ob.data
+ split = layout.split()
+
+ col = split.column()
+ row = col.row(align=True)
+ row.prop(md, "factor")
+ row.prop(md, "random", text="", icon="TIME", toggle=True)
+ row = col.row()
+ row.enabled = md.random
+ row.prop(md, "step")
+ col.prop(md, "full_stroke")
+ col.prop(md, "move_extreme")
+
+ col = split.column()
+ col.label("Layer:")
+ row = col.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+ row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT")
+
+ col.label("Vertex Group:")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT")
+
+ row = col.row(align=True)
+ row.prop(md, "pass_index", text="Pass")
+ row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
+
+ row = layout.row(align=True)
+ row.label("Affect:")
+ row = layout.row(align=True)
+ row.prop(md, "affect_position", text="Position", icon='MESH_DATA', toggle=True)
+ row.prop(md, "affect_strength", text="Strength", icon='COLOR', toggle=True)
+ row.prop(md, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
+ row.prop(md, "affect_uv", text="UV", icon='MOD_UVPROJECT', toggle=True)
+
+ def GP_SMOOTH(self, layout, ob, md):
+ gpd = ob.data
+ row = layout.row(align=False)
+ row.prop(md, "factor")
+ row.prop(md, "step")
+
+ split = layout.split()
+ col = split.column()
+ col.label("Layer:")
+ row = col.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+ row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT")
+
+ col = split.column()
+ col.label("Vertex Group:")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT")
+
+ row = col.row(align=True)
+ row.prop(md, "pass_index", text="Pass")
+ row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
+
+ row = layout.row(align=True)
+ row.label("Affect:")
+ row = layout.row(align=True)
+ row.prop(md, "affect_position", text="Position", icon='MESH_DATA', toggle=True)
+ row.prop(md, "affect_strength", text="Strength", icon='COLOR', toggle=True)
+ row.prop(md, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
+ row.prop(md, "affect_uv", text="UV", icon='MOD_UVPROJECT', toggle=True)
+
+ def GP_SUBDIV(self, layout, ob, md):
+ gpd = ob.data
+ split = layout.split()
+
+ col = split.column()
+ row = col.row(align=True)
+ row.prop(md, "level")
+ row.prop(md, "simple", text="", icon="PARTICLE_POINT")
+ row = col.row(align=True)
+ row.prop(md, "pass_index", text="Pass")
+ row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
+
+ col = split.column()
+ col.label("Layer:")
+ row = col.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+ row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT")
+
+ def GP_SIMPLIFY(self, layout, ob, md):
+ gpd = ob.data
+
+ row = layout.row()
+ row.prop(md, "mode")
+
+ split = layout.split()
+
+ col = split.column()
+ col.label("Settings:")
+ row = col.row(align=True)
+ row.enabled = md.mode == 'FIXED'
+ row.prop(md, "step")
+
+ row = col.row(align=True)
+ row.enabled = not md.mode == 'FIXED'
+ row.prop(md, "factor")
+
+ col = split.column()
+ col.label("Layer:")
+ row = col.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+
+ row = col.row(align=True)
+ row.prop(md, "pass_index", text="Pass")
+ row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
+
+ def GP_THICK(self, layout, ob, md):
+ gpd = ob.data
+ split = layout.split()
+
+ col = split.column()
+ row = col.row(align=True)
+ row.prop(md, "thickness")
+ row = col.row(align=True)
+ row.prop(md, "pass_index", text="Pass")
+ row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
+
+ col.prop(md, "normalize_thickness")
+
+ col = split.column()
+ col.label("Layer:")
+ row = col.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+ row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT")
+
+ col.label("Vertex Group:")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT")
+
+ if not md.normalize_thickness:
+ split = layout.split()
+ col = split.column()
+ col.prop(md, "use_custom_curve")
+
+ if md.use_custom_curve:
+ col.template_curve_mapping(md, "curve")
+
+ def GP_TINT(self, layout, ob, md):
+ gpd = ob.data
+ split = layout.split()
+
+ col = split.column()
+ col.prop(md, "color")
+ col.prop(md, "factor")
+
+ col = split.column()
+ col.label("Layer:")
+ row = col.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+ row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT")
+ row = col.row(align=True)
+ row.prop(md, "pass_index", text="Pass")
+ row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
+
+ row = layout.row()
+ row.prop(md, "create_colors")
+
+ def GP_COLOR(self, layout, ob, md):
+ gpd = ob.data
+ split = layout.split()
+
+ col = split.column()
+ col.label("Color:")
+ col.prop(md, "hue", text="H")
+ col.prop(md, "saturation", text="S")
+ col.prop(md, "value", text="V")
+
+ col = split.column()
+ col.label("Layer:")
+ row = col.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+ row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT")
+ row = col.row(align=True)
+ row.prop(md, "pass_index", text="Pass")
+ row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
+
+ row = layout.row()
+ row.prop(md, "create_colors")
+
+ def GP_OPACITY(self, layout, ob, md):
+ gpd = ob.data
+ split = layout.split()
+
+ col = split.column()
+ col.label("Opacity:")
+ col.prop(md, "factor")
+
+ col = split.column()
+ col.label("Layer:")
+ row = col.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+ row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT")
+
+ col.label("Vertex Group:")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT")
+
+ row = col.row(align=True)
+ row.prop(md, "pass_index", text="Pass")
+ row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
+
+ def GP_INSTANCE(self, layout, ob, md):
+ gpd = ob.data
+
+ col = layout.column()
+ col.prop(md, "count")
+ col.prop(md, "use_make_objects")
+
+ split = layout.split()
+ col = split.column()
+ col.label("Offset:")
+ col.prop(md, "offset", text="")
+
+ col = split.column()
+ col.label("Shift:")
+ col.prop(md, "shift", text="")
+ row = col.row(align=True)
+ row.prop(md, "lock_axis", expand=True)
+
+ split = layout.split()
+ col = split.column()
+ col.label("Rotation:")
+ col.prop(md, "rotation", text="")
+ col.separator()
+ row = col.row(align=True)
+ row.prop(md, "random_rot", text="", icon="TIME", toggle=True)
+ row.prop(md, "rot_factor", text="")
+
+ col = split.column()
+ col.label("Scale:")
+ col.prop(md, "scale", text="")
+ col.separator()
+ row = col.row(align=True)
+ row.prop(md, "random_scale", text="", icon="TIME", toggle=True)
+ row.prop(md, "scale_factor", text="")
+
+ split = layout.split()
+ col = split.column()
+ col.label("Layer:")
+ row = col.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+ row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT")
+ row = col.row(align=True)
+ row.prop(md, "pass_index", text="Pass")
+ row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
+
+ def GP_BUILD(self, layout, ob, md):
+ gpd = ob.data
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(md, "mode")
+ if md.mode == 'CONCURRENT':
+ col.prop(md, "concurrent_time_alignment")
+ else:
+ col.separator() # For spacing
+ col.separator()
+ col.separator()
+
+ col.prop(md, "transition")
+ sub = col.column(align=True)
+ sub.prop(md, "start_delay")
+ sub.prop(md, "length")
+
+ col = split.column(align=True)
+ col.prop(md, "use_restrict_frame_range")
+ sub = col.column(align=True)
+ sub.active = md.use_restrict_frame_range
+ sub.prop(md, "frame_start", text="Start")
+ sub.prop(md, "frame_end", text="End")
+ col.separator()
+
+ col.label("Layer:")
+ row = col.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+ row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT")
+
+ def GP_LATTICE(self, layout, ob, md):
+ gpd = ob.data
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Object:")
+ col.prop(md, "object", text="")
+
+ col = split.column()
+ col.label("Layer:")
+ row = col.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+ row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT")
+
+ col.label("Vertex Group:")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT")
+
+ row = col.row(align=True)
+ row.prop(md, "pass_index", text="Pass")
+ row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
+
+ layout.separator()
+ layout.prop(md, "strength", slider=True)
+
+ def GP_MIRROR(self, layout, ob, md):
+ gpd = ob.data
+
+ row = layout.row(align=True)
+ row.prop(md, "x_axis")
+ row.prop(md, "y_axis")
+ row.prop(md, "z_axis")
+
+ # GPXX: Not implemented yet
+ # layout.separator()
+ # layout.prop(md, "clip")
+
+ layout.label("Layer:")
+ row = layout.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+ row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT")
+
+ row = layout.row(align=True)
+ row.prop(md, "pass_index", text="Pass")
+ row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
+
+ layout.label(text="Object:")
+ layout.prop(md, "object", text="")
+
+
+ def GP_HOOK(self, layout, ob, md):
+ gpd = ob.data
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Object:")
+ col.prop(md, "object", text="")
+ if md.object and md.object.type == 'ARMATURE':
+ col.label(text="Bone:")
+ col.prop_search(md, "subtarget", md.object.data, "bones", text="")
+
+ col = split.column()
+ col.label("Layer:")
+ row = col.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+ row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT")
+
+ col.label("Vertex Group:")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT")
+
+ row = col.row(align=True)
+ row.prop(md, "pass_index", text="Pass")
+ row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
+
+ use_falloff = (md.falloff_type != 'NONE')
+ split = layout.split()
+
+ layout.separator()
+
+ row = layout.row(align=True)
+ if use_falloff:
+ row.prop(md, "falloff_radius")
+ row.prop(md, "strength", slider=True)
+ layout.prop(md, "falloff_type")
+
+ col = layout.column()
+ if use_falloff:
+ if md.falloff_type == 'CURVE':
+ col.template_curve_mapping(md, "falloff_curve")
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(md, "use_falloff_uniform")
+
+
+ def GP_OFFSET(self, layout, ob, md):
+ gpd = ob.data
+ split = layout.split()
+
+ col = split.column()
+ col.prop(md, "location")
+ col.prop(md, "scale")
+
+ col = split.column()
+ col.prop(md, "rotation")
+
+
+ col.label("Layer:")
+ row = col.row(align=True)
+ row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
+ row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT")
+
+ col.label("Vertex Group:")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT")
+
+ row = col.row(align=True)
+ row.prop(md, "pass_index", text="Pass")
+ row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
+
+
classes = (
DATA_PT_modifiers,
+ DATA_PT_gpencil_modifiers,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/properties_data_shaderfx.py b/release/scripts/startup/bl_ui/properties_data_shaderfx.py
new file mode 100644
index 00000000000..5010f56d234
--- /dev/null
+++ b/release/scripts/startup/bl_ui/properties_data_shaderfx.py
@@ -0,0 +1,134 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+import bpy
+from bpy.types import Panel
+from bpy.app.translations import pgettext_iface as iface_
+
+
+class ShaderFxButtonsPanel:
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "shaderfx"
+ bl_options = {'HIDE_HEADER'}
+
+class DATA_PT_shader_fx(ShaderFxButtonsPanel, Panel):
+ bl_label = "Effects"
+
+ @classmethod
+ def poll(cls, context):
+ return True
+ ob = context.object
+ return ob and ob.type == 'GPENCIL'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ ob = context.object
+
+ layout.operator_menu_enum("object.shaderfx_add", "type")
+
+ for fx in ob.shader_effects:
+ box = layout.template_shaderfx(fx)
+ if box:
+ # match enum type to our functions, avoids a lookup table.
+ getattr(self, fx.type)(box, fx)
+
+ # the mt.type enum is (ab)used for a lookup on function names
+ # ...to avoid lengthy if statements
+ # so each type must have a function here.
+
+ def FX_BLUR(self, layout, fx):
+
+ layout.prop(fx, "factor", text="Factor")
+ layout.prop(fx, "samples", text="Samples")
+
+ layout.separator()
+ layout.prop(fx, "use_dof_mode")
+ if fx.use_dof_mode:
+ layout.prop(fx, "coc")
+
+ def FX_COLORIZE(self, layout, fx):
+ layout.prop(fx, "mode", text="Mode")
+
+ if fx.mode == 'BITONE':
+ layout.prop(fx, "low_color", text="Low Color")
+ if fx.mode == 'CUSTOM':
+ layout.prop(fx, "low_color", text="Color")
+
+ if fx.mode == 'BITONE':
+ layout.prop(fx, "high_color", text="High Color")
+
+ if fx.mode in {'BITONE', 'CUSTOM', 'TRANSPARENT'}:
+ layout.prop(fx, "factor")
+
+ def FX_WAVE(self, layout,fx):
+ layout.prop(fx, "orientation", expand=True)
+
+ layout.separator()
+ layout.prop(fx, "amplitude")
+ layout.prop(fx, "period")
+ layout.prop(fx, "phase")
+
+ def FX_PIXEL(self, layout, fx):
+ layout.prop(fx, "size", text="Size")
+
+ layout.prop(fx, "use_lines", text="Display Lines")
+
+ col = layout.column()
+ col.enabled = fx.use_lines
+ col.prop(fx, "color")
+
+ def FX_RIM(self, layout, fx):
+ layout.prop(fx, "offset", text="Offset")
+
+ layout.prop(fx, "rim_color")
+ layout.prop(fx, "mask_color")
+ layout.prop(fx, "mode")
+ layout.prop(fx, "blur")
+ layout.prop(fx, "samples")
+
+ def FX_SWIRL(self, layout, fx):
+ layout.prop(fx, "object", text="Object")
+
+ layout.prop(fx, "radius")
+ layout.prop(fx, "angle")
+
+ layout.prop(fx, "transparent")
+
+ def FX_FLIP(self, layout, fx):
+ layout.prop(fx, "flip_horizontal")
+ layout.prop(fx, "flip_vertical")
+
+ def FX_LIGHT(self, layout, fx):
+ layout.prop(fx, "object", text="Object")
+
+ layout.prop(fx, "energy")
+ layout.prop(fx, "ambient")
+
+
+classes = (
+ DATA_PT_shader_fx,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 55b798d103a..252f87d369f 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -18,45 +18,30 @@
# <pep8 compliant>
-
+import bpy
from bpy.types import Menu, UIList
from bpy.app.translations import pgettext_iface as iface_
def gpencil_stroke_placement_settings(context, layout):
if context.space_data.type == 'VIEW_3D':
- propname = "gpencil_stroke_placement_view3d"
+ propname = "annotation_stroke_placement_view3d"
elif context.space_data.type == 'SEQUENCE_EDITOR':
- propname = "gpencil_stroke_placement_sequencer_preview"
+ propname = "annotation_stroke_placement_sequencer_preview"
elif context.space_data.type == 'IMAGE_EDITOR':
- propname = "gpencil_stroke_placement_image_editor"
+ propname = "annotation_stroke_placement_image_editor"
else:
- propname = "gpencil_stroke_placement_view2d"
+ propname = "annotation_stroke_placement_view2d"
ts = context.tool_settings
col = layout.column(align=True)
- col.label(text="Stroke Placement:")
-
- row = col.row(align=True)
- row.prop_enum(ts, propname, 'VIEW')
- row.prop_enum(ts, propname, 'CURSOR')
-
- if context.space_data.type == 'VIEW_3D':
+ if context.space_data.type != 'VIEW_3D':
+ col.label(text="Stroke Placement:")
row = col.row(align=True)
- row.prop_enum(ts, propname, 'SURFACE')
- row.prop_enum(ts, propname, 'STROKE')
-
- row = col.row(align=False)
- row.active = getattr(ts, propname) in {'SURFACE', 'STROKE'}
- row.prop(ts, "use_gpencil_stroke_endpoints")
-
- if context.scene.tool_settings.gpencil_stroke_placement_view3d == 'CURSOR':
- row = col.row(align=True)
- row.label("Lock axis:")
- row = col.row(align=True)
- row.prop(ts.gpencil_sculpt, "lockaxis", expand=True)
+ row.prop_enum(ts, propname, 'VIEW')
+ row.prop_enum(ts, propname, 'CURSOR', text="Cursor")
def gpencil_active_brush_settings_simple(context, layout):
@@ -73,7 +58,7 @@ def gpencil_active_brush_settings_simple(context, layout):
row.operator_menu_enum("gpencil.brush_change", "brush", text="", icon='BRUSH_DATA')
row.prop(brush, "name", text="")
- col.prop(brush, "line_width", slider=True)
+ col.prop(brush, "size", slider=True)
row = col.row(align=True)
row.prop(brush, "use_random_pressure", text="", icon='RNDCURVE')
row.prop(brush, "pen_sensitivity_factor", slider=True)
@@ -90,6 +75,7 @@ def gpencil_active_brush_settings_simple(context, layout):
row.prop(brush, "angle_factor", text="Factor", slider=True)
+# XXX: To be replaced with active tools
class GreasePencilDrawingToolsPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
@@ -99,8 +85,7 @@ class GreasePencilDrawingToolsPanel:
@classmethod
def poll(cls, context):
- # XXX - disabled in 2.8 branch.
- return False
+ return True
@staticmethod
def draw(self, context):
@@ -113,12 +98,12 @@ class GreasePencilDrawingToolsPanel:
col.label(text="Draw:")
row = col.row(align=True)
- row.operator("gpencil.draw", icon='GREASEPENCIL', text="Draw").mode = 'DRAW'
- row.operator("gpencil.draw", icon='FORCE_CURVE', text="Erase").mode = 'ERASER' # XXX: Needs a dedicated icon
+ row.operator("gpencil.annotate", icon='GREASEPENCIL', text="Draw").mode = 'DRAW'
+ row.operator("gpencil.annotate", icon='FORCE_CURVE', text="Erase").mode = 'ERASER' # XXX: Needs a dedicated icon
row = col.row(align=True)
- row.operator("gpencil.draw", icon='LINE_DATA', text="Line").mode = 'DRAW_STRAIGHT'
- row.operator("gpencil.draw", icon='MESH_DATA', text="Poly").mode = 'DRAW_POLY'
+ row.operator("gpencil.annotate", icon='LINE_DATA', text="Line").mode = 'DRAW_STRAIGHT'
+ row.operator("gpencil.annotate", icon='MESH_DATA', text="Poly").mode = 'DRAW_POLY'
col.separator()
@@ -126,15 +111,15 @@ class GreasePencilDrawingToolsPanel:
sub.operator("gpencil.blank_frame_add", icon='NEW')
sub.operator("gpencil.active_frames_delete_all", icon='X', text="Delete Frame(s)")
- sub = col.column(align=True)
- sub.prop(context.tool_settings, "use_gpencil_additive_drawing", text="Additive Drawing")
- sub.prop(context.tool_settings, "use_gpencil_continuous_drawing", text="Continuous Drawing")
- sub.prop(context.tool_settings, "use_gpencil_draw_onback", text="Draw on Back")
+ #sub = col.column(align=True)
+ #sub.prop(context.tool_settings, "use_gpencil_additive_drawing", text="Additive Drawing")
+ #sub.prop(context.tool_settings, "use_gpencil_continuous_drawing", text="Continuous Drawing")
+ #sub.prop(context.tool_settings, "use_gpencil_draw_onback", text="Draw on Back")
col.separator()
col.separator()
- if context.space_data.type in {'VIEW_3D', 'CLIP_EDITOR'}:
+ if context.space_data.type in {'CLIP_EDITOR'}:
col.separator()
col.label("Data Source:")
row = col.row(align=True)
@@ -143,8 +128,8 @@ class GreasePencilDrawingToolsPanel:
elif is_clip_editor:
row.prop(context.space_data, "grease_pencil_source", expand=True)
- col.separator()
- col.separator()
+ #col.separator()
+ #col.separator()
gpencil_stroke_placement_settings(context, col)
@@ -157,28 +142,16 @@ class GreasePencilDrawingToolsPanel:
col = layout.column(align=True)
col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True)
- if is_3d_view:
- col.separator()
- col.separator()
-
- col.label(text="Tools:")
- col.operator_menu_enum("gpencil.convert", text="Convert to Geometry...", property="type")
- col.operator("view3d.ruler")
-
class GreasePencilStrokeEditPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
bl_label = "Edit Strokes"
- bl_category = "Grease Pencil"
+ bl_category = "Tools"
bl_region_type = 'TOOLS'
- bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
- # XXX - disabled in 2.8 branch.
- return False
-
if context.gpencil_data is None:
return False
@@ -204,7 +177,7 @@ class GreasePencilStrokeEditPanel:
col.operator("gpencil.select_linked")
col.operator("gpencil.select_more")
col.operator("gpencil.select_less")
- col.operator("gpencil.palettecolor_select")
+ col.operator("gpencil.select_alternate")
layout.label(text="Edit:")
row = layout.row(align=True)
@@ -228,258 +201,124 @@ class GreasePencilStrokeEditPanel:
layout.separator()
- col = layout.column(align=True)
- col.operator("transform.bend", text="Bend")
- col.operator("transform.mirror", text="Mirror")
- col.operator("transform.shear", text="Shear")
- col.operator("transform.tosphere", text="To Sphere")
-
layout.separator()
col = layout.column(align=True)
col.operator_menu_enum("gpencil.stroke_arrange", text="Arrange Strokes...", property="direction")
col.operator("gpencil.stroke_change_color", text="Move to Color")
- if is_3d_view:
- layout.separator()
-
layout.separator()
col = layout.column(align=True)
col.operator("gpencil.stroke_subdivide", text="Subdivide")
- col.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
- col.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY'
- col.operator("gpencil.stroke_flip", text="Flip Direction")
-
- gpd = context.gpencil_data
- if gpd:
- col.prop(gpd, "show_stroke_direction", text="Show Directions")
-
- if is_3d_view:
- layout.separator()
- layout.operator_menu_enum("gpencil.reproject", text="Reproject Strokes...", property="type")
-
-
-class GreasePencilInterpolatePanel:
- bl_space_type = 'VIEW_3D'
- bl_label = "Interpolate"
- bl_category = "Grease Pencil"
- bl_region_type = 'TOOLS'
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
- # XXX - disabled in 2.8 branch.
- return False
-
- if context.gpencil_data is None:
- return False
- elif context.space_data.type != 'VIEW_3D':
- return False
-
- gpd = context.gpencil_data
- return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
-
- @staticmethod
- def draw(self, context):
- layout = self.layout
- settings = context.tool_settings.gpencil_interpolate
-
- col = layout.column(align=True)
- col.operator("gpencil.interpolate", text="Interpolate")
- col.operator("gpencil.interpolate_sequence", text="Sequence")
- col.operator("gpencil.interpolate_reverse", text="Remove Breakdowns")
-
- col = layout.column(align=True)
- col.label(text="Options:")
- col.prop(settings, "interpolate_all_layers")
- col.prop(settings, "interpolate_selected_only")
-
- col = layout.column(align=True)
- col.label(text="Sequence Options:")
- col.prop(settings, "type")
- if settings.type == 'CUSTOM':
- box = layout.box()
- # TODO: Options for loading/saving curve presets?
- box.template_curve_mapping(settings, "interpolation_curve", brush=True)
- elif settings.type != 'LINEAR':
- col.prop(settings, "easing")
-
- if settings.type == 'BACK':
- layout.prop(settings, "back")
- elif setting.type == 'ELASTIC':
- sub = layout.column(align=True)
- sub.prop(settings, "amplitude")
- sub.prop(settings, "period")
-
-
-class GreasePencilBrushPanel:
- # subclass must set
- # bl_space_type = 'IMAGE_EDITOR'
- bl_label = "Drawing Brushes"
- bl_category = "Grease Pencil"
- bl_region_type = 'TOOLS'
-
- @classmethod
- def poll(cls, context):
- # XXX - disabled in 2.8 branch.
- return False
+ row = col.row(align=True)
+ row.operator("gpencil.stroke_simplify_fixed", text="Simplify")
+ row.operator("gpencil.stroke_simplify", text="Adaptative")
- @staticmethod
- def draw(self, context):
- layout = self.layout
+ col.separator()
- row = layout.row()
- col = row.column()
- ts = context.scene.tool_settings
- if len(ts.gpencil_brushes) >= 2:
- brows = 3
- else:
- brows = 2
- col.template_list("GPENCIL_UL_brush", "", ts, "gpencil_brushes", ts.gpencil_brushes, "active_index", rows=brows)
+ row = col.row(align=True)
+ row.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
+ row.operator("gpencil.stroke_join", text="& Copy").type = 'JOINCOPY'
- col = row.column()
+ col.operator("gpencil.stroke_flip", text="Flip Direction")
- sub = col.column(align=True)
- sub.operator("gpencil.brush_add", icon='ZOOMIN', text="")
- sub.operator("gpencil.brush_remove", icon='ZOOMOUT', text="")
- sub.menu("GPENCIL_MT_brush_specials", icon='DOWNARROW_HLT', text="")
- brush = context.active_gpencil_brush
- if brush:
- if len(ts.gpencil_brushes) > 1:
- col.separator()
- sub = col.column(align=True)
- sub.operator("gpencil.brush_move", icon='TRIA_UP', text="").type = 'UP'
- sub.operator("gpencil.brush_move", icon='TRIA_DOWN', text="").type = 'DOWN'
+ if is_3d_view:
+ layout.separator()
- # Brush details
- if brush is not None:
- row = layout.row()
- row.prop(brush, "line_width")
- row = layout.row(align=True)
- row.prop(brush, "use_random_pressure", text="", icon='RNDCURVE')
- row.prop(brush, "pen_sensitivity_factor", slider=True)
- row.prop(brush, "use_pressure", text="", icon='STYLUS_PRESSURE')
- row = layout.row(align=True)
- row.prop(brush, "use_random_strength", text="", icon='RNDCURVE')
- row.prop(brush, "strength", slider=True)
- row.prop(brush, "use_strength_pressure", text="", icon='STYLUS_PRESSURE')
- row = layout.row(align=True)
- row.prop(brush, "random_press", slider=True)
+ col = layout.column(align=True)
+ col.operator_menu_enum("gpencil.stroke_separate", text="Separate...", property="mode")
+ col.operator("gpencil.stroke_split", text="Split")
- row = layout.row(align=True)
- row.prop(brush, "jitter", slider=True)
- row.prop(brush, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE')
- row = layout.row()
- row.prop(brush, "angle", slider=True)
- row.prop(brush, "angle_factor", text="Factor", slider=True)
-
- box = layout.box()
- col = box.column(align=True)
- col.label(text="Stroke Quality:")
- col.prop(brush, "pen_smooth_factor")
- col.prop(brush, "pen_smooth_steps")
- col.separator()
- row = col.row(align=False)
- row.prop(brush, "pen_subdivision_steps")
- row.prop(brush, "random_subdiv", text="Randomness", slider=True)
+ col = layout.column(align=True)
+ col.label(text="Cleanup:")
+ col.operator_menu_enum("gpencil.reproject", text="Reproject Strokes...", property="type")
+ col.operator_menu_enum("gpencil.frame_clean_fill", text="Clean Boundary Strokes...", property="mode")
class GreasePencilStrokeSculptPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
bl_label = "Sculpt Strokes"
- bl_category = "Grease Pencil"
- bl_region_type = 'TOOLS'
-
- @classmethod
- def poll(cls, context):
- # XXX - disabled in 2.8 branch.
- return False
-
- if context.gpencil_data is None:
- return False
-
- gpd = context.gpencil_data
- return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
+ bl_category = "Tools"
@staticmethod
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
settings = context.tool_settings.gpencil_sculpt
tool = settings.tool
brush = settings.brush
- layout.column().prop(settings, "tool")
+ layout.template_icon_view(settings, "tool", show_labels=True)
- col = layout.column()
- col.prop(brush, "size", slider=True)
- row = col.row(align=True)
+ layout.prop(brush, "size", slider=True)
+ row = layout.row(align=True)
row.prop(brush, "strength", slider=True)
row.prop(brush, "use_pressure_strength", text="")
- col.prop(brush, "use_falloff")
- if tool in {'SMOOTH', 'RANDOMIZE'}:
- row = layout.row(align=True)
- row.prop(settings, "affect_position", text="Position", icon='MESH_DATA', toggle=True)
- row.prop(settings, "affect_strength", text="Strength", icon='COLOR', toggle=True)
- row.prop(settings, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
- layout.separator()
+ layout.prop(brush, "use_falloff")
- if tool == 'THICKNESS':
- layout.row().prop(brush, "direction", expand=True)
- elif tool == 'PINCH':
- row = layout.row(align=True)
- row.prop_enum(brush, "direction", 'ADD', text="Pinch")
- row.prop_enum(brush, "direction", 'SUBTRACT', text="Inflate")
- elif settings.tool == 'TWIST':
- row = layout.row(align=True)
- row.prop_enum(brush, "direction", 'SUBTRACT', text="CW")
- row.prop_enum(brush, "direction", 'ADD', text="CCW")
+ if tool in {'SMOOTH', 'RANDOMIZE'}:
+ layout.prop(settings, "affect_position", text="Affect Position")
+ layout.prop(settings, "affect_strength", text="Affect Strength")
+ layout.prop(settings, "affect_thickness", text="Affect Thickness")
- row = layout.row(align=True)
- row.prop(settings, "use_select_mask")
- row = layout.row(align=True)
- row.prop(settings, "selection_alpha", slider=True)
+ if tool == 'SMOOTH':
+ layout.prop(brush, "affect_pressure")
- if tool == 'SMOOTH':
- layout.prop(brush, "affect_pressure")
+ layout.prop(settings, "affect_uv", text="Affect UV")
+ if tool in {'THICKNESS', 'PINCH', 'TWIST'}:
+ layout.prop(brush, "direction", expand=True)
-class GreasePencilBrushCurvesPanel:
- # subclass must set
- # bl_space_type = 'IMAGE_EDITOR'
- bl_label = "Brush Curves"
- bl_category = "Grease Pencil"
- bl_region_type = 'TOOLS'
+
+# GP Object Tool Settings
+class GreasePencilAppearancePanel:
+ bl_label = "Brush Appearance"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
- # XXX - disabled in 2.8 branch.
- return False
-
- if context.active_gpencil_brush is None:
- return False
-
- brush = context.active_gpencil_brush
- return bool(brush)
+ ob = context.active_object
+ return ob and ob.type == 'GPENCIL'
@staticmethod
def draw(self, context):
layout = self.layout
- brush = context.active_gpencil_brush
- # Brush
- layout.label("Sensitivity")
- box = layout.box()
- box.template_curve_mapping(brush, "curve_sensitivity", brush=True)
+ layout.use_property_split = True
+ layout.use_property_decorate = False
- layout.label("Strength")
- box = layout.box()
- box.template_curve_mapping(brush, "curve_strength", brush=True)
+ ob = context.active_object
- layout.label("Jitter")
- box = layout.box()
- box.template_curve_mapping(brush, "curve_jitter", brush=True)
+ if ob.mode == 'GPENCIL_PAINT':
+ brush = context.active_gpencil_brush
+ gp_settings = brush.gpencil_settings
+
+ layout.prop(gp_settings, "gpencil_brush_type", text="Brush Type")
+
+ sub = layout.column(align=True)
+ sub.enabled = not brush.use_custom_icon
+ sub.prop(gp_settings, "gp_icon", text="Icon")
+
+ layout.prop(brush, "use_custom_icon")
+ sub = layout.column()
+ sub.active = brush.use_custom_icon
+ sub.prop(brush, "icon_filepath", text="")
+
+ layout.prop(gp_settings, "use_cursor", text="Show Brush")
+
+ if gp_settings.gpencil_brush_type == 'FILL':
+ layout.prop(brush, "cursor_color_add", text="Color")
+
+ elif ob.mode in ('GPENCIL_SCULPT', 'GPENCIL_WEIGHT'):
+ settings = context.tool_settings.gpencil_sculpt
+ brush = settings.brush
+
+ col = layout.column(align=True)
+ col.prop(brush, "use_cursor", text="Show Brush")
+ col.row().prop(brush, "cursor_color_add", text="Add")
+ col.row().prop(brush, "cursor_color_sub", text="Subtract")
###############################
@@ -539,6 +378,7 @@ class GPENCIL_MT_pie_tool_palette(Menu):
col.operator("gpencil.select_border", text="Border Select", icon='BORDER_RECT')
col.operator("gpencil.select_circle", text="Circle Select", icon='META_EMPTY')
col.operator("gpencil.select_lasso", text="Lasso Select", icon='BORDER_LASSO')
+ col.operator("gpencil.select_alternate", text="Alternate Select", icon='BORDER_LASSO')
# SW - Edit Tools
col = pie.column()
@@ -566,7 +406,7 @@ class GPENCIL_MT_pie_settings_palette(Menu):
pie = layout.menu_pie()
gpd = context.gpencil_data
gpl = context.active_gpencil_layer
- palcolor = context.active_gpencil_palettecolor
+ palcolor = None #context.active_gpencil_palettecolor
brush = context.active_gpencil_brush
is_editmode = bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes)
@@ -737,6 +577,16 @@ class GPENCIL_MT_snap(Menu):
layout.operator("view3d.snap_cursor_to_grid", text="Cursor to Grid")
+class GPENCIL_MT_separate(Menu):
+ bl_label = "Separate"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator("gpencil.stroke_separate", text="Selected Points").mode = 'POINT'
+ layout.operator("gpencil.stroke_separate", text="Selected Strokes").mode = 'STROKE'
+ layout.operator("gpencil.stroke_separate", text="Active Layer").mode = 'LAYER'
+
+
class GPENCIL_MT_gpencil_edit_specials(Menu):
bl_label = "GPencil Specials"
@@ -747,6 +597,14 @@ class GPENCIL_MT_gpencil_edit_specials(Menu):
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("gpencil.stroke_subdivide", text="Subdivide")
+ layout.operator("gpencil.stroke_simplify_fixed", text="Simplify")
+ layout.operator("gpencil.stroke_simplify", text="Simplify Adaptative")
+
+ layout.separator()
+ layout.menu("GPENCIL_MT_separate", text="Separate")
+
+ layout.separator()
+ layout.operator("gpencil.stroke_split", text="Split")
layout.separator()
@@ -754,167 +612,129 @@ class GPENCIL_MT_gpencil_edit_specials(Menu):
layout.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY'
layout.operator("gpencil.stroke_flip", text="Flip Direction")
+ layout.separator()
+ layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame")
+ layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame All Layers").mode = 'ALL'
+
if is_3d_view:
layout.separator()
layout.operator("gpencil.reproject")
-###############################
-
-
-class GPENCIL_UL_brush(UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
- # assert(isinstance(item, bpy.types.GPencilBrush)
- brush = item
-
- if self.layout_type in {'DEFAULT', 'COMPACT'}:
- row = layout.row(align=True)
- row.prop(brush, "name", text="", emboss=False, icon='BRUSH_DATA')
- elif self.layout_type == 'GRID':
- layout.alignment = 'CENTER'
- layout.label(text="", icon_value=icon)
-
-
-class GPENCIL_UL_palettecolor(UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
- # assert(isinstance(item, bpy.types.PaletteColor)
- palcolor = item
-
- if self.layout_type in {'DEFAULT', 'COMPACT'}:
- if palcolor.lock:
- layout.active = False
-
- split = layout.split(percentage=0.25)
- row = split.row(align=True)
- row.enabled = not palcolor.lock
- row.prop(palcolor, "color", text="", emboss=palcolor.is_stroke_visible)
- row.prop(palcolor, "fill_color", text="", emboss=palcolor.is_fill_visible)
- split.prop(palcolor, "name", text="", emboss=False)
-
- row = layout.row(align=True)
- row.prop(palcolor, "lock", text="", emboss=False)
- row.prop(palcolor, "hide", text="", emboss=False)
- if palcolor.ghost is True:
- icon = 'GHOST_DISABLED'
- else:
- icon = 'GHOST_ENABLED'
- row.prop(palcolor, "ghost", text="", icon=icon, emboss=False)
-
- elif self.layout_type == 'GRID':
- layout.alignment = 'CENTER'
- layout.label(text="", icon_value=icon)
-
+class GPENCIL_MT_gpencil_sculpt_specials(Menu):
+ bl_label = "GPencil Specials"
-class GPENCIL_UL_layer(UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
- # assert(isinstance(item, bpy.types.GPencilLayer)
- gpl = item
+ def draw(self, context):
+ layout = self.layout
+ is_3d_view = context.space_data.type == 'VIEW_3D'
- if self.layout_type in {'DEFAULT', 'COMPACT'}:
- if gpl.lock:
- layout.active = False
+ layout.operator_context = 'INVOKE_REGION_WIN'
- row = layout.row(align=True)
- if gpl.is_parented:
- icon = 'BONE_DATA'
- else:
- icon = 'BLANK1'
+ layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame")
+ layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame All Layers").mode = 'ALL'
- row.label(text="", icon=icon)
- row.prop(gpl, "info", text="", emboss=False)
+ layout.separator()
- row = layout.row(align=True)
- row.prop(gpl, "lock", text="", emboss=False)
- row.prop(gpl, "hide", text="", emboss=False)
- row.prop(gpl, "unlock_color", text="", emboss=False)
- elif self.layout_type == 'GRID':
- layout.alignment = 'CENTER'
- layout.label(text="", icon_value=icon)
+ layout.operator("gpencil.stroke_subdivide", text="Subdivide")
+ layout.operator("gpencil.stroke_simplify_fixed", text="Simplify")
+ layout.operator("gpencil.stroke_simplify", text="Simplify Adaptative")
-class GPENCIL_MT_layer_specials(Menu):
- bl_label = "Layer"
+class GPENCIL_MT_gpencil_draw_specials(Menu):
+ bl_label = "GPencil Draw Specials"
def draw(self, context):
layout = self.layout
+ is_3d_view = context.space_data.type == 'VIEW_3D'
- layout.operator("gpencil.layer_duplicate", icon='COPY_ID') # XXX: needs a dedicated icon
-
- layout.separator()
+ layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("gpencil.reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
- layout.operator("gpencil.hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True
+ layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame")
+ layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame All Layers").mode = 'ALL'
layout.separator()
+ layout.operator("gpencil.primitive", text="Line", icon='IPO_CONSTANT').type = 'LINE'
+ layout.operator("gpencil.primitive", text="Rectangle", icon='UV_FACESEL').type = 'BOX'
+ layout.operator("gpencil.primitive", text="Circle", icon='ANTIALIASED').type = 'CIRCLE'
- layout.operator("gpencil.lock_all", icon='LOCKED', text="Lock All")
- layout.operator("gpencil.unlock_all", icon='UNLOCKED', text="UnLock All")
-
+ # colors
layout.separator()
+ layout.operator("gpencil.colorpick", text="Colors", icon="GROUP_VCOL")
- layout.operator("gpencil.layer_merge", icon='NLA', text="Merge Down")
-
-class GPENCIL_MT_brush_specials(Menu):
- bl_label = "Layer"
+class GPENCIL_MT_gpencil_draw_delete(Menu):
+ bl_label = "GPencil Draw Delete"
def draw(self, context):
layout = self.layout
- layout.operator("gpencil.brush_copy", icon='PASTEDOWN', text="Copy Current Drawing Brush")
- layout.operator("gpencil.brush_presets_create", icon='HELP', text="Create a Set of Predefined Brushes")
-
+ is_3d_view = context.space_data.type == 'VIEW_3D'
-class GPENCIL_MT_palettecolor_specials(Menu):
- bl_label = "Layer"
+ layout.operator_context = 'INVOKE_REGION_WIN'
- def draw(self, context):
- layout = self.layout
+ layout.operator("gpencil.active_frames_delete_all", text="Delete Frame")
- layout.operator("gpencil.palettecolor_reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
- layout.operator("gpencil.palettecolor_hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True
- layout.separator()
+class GPENCIL_UL_annotation_layer(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ # assert(isinstance(item, bpy.types.GPencilLayer)
+ gpl = item
+ gpd = context.gpencil_data
- layout.operator("gpencil.palettecolor_lock_all", icon='LOCKED', text="Lock All")
- layout.operator("gpencil.palettecolor_unlock_all", icon='UNLOCKED', text="UnLock All")
- layout.operator("gpencil.palettecolor_copy", icon='PASTEDOWN', text="Copy Color")
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ if gpl.lock:
+ layout.active = False
- layout.separator()
+ split = layout.split(percentage=0.2)
+ split.prop(gpl, "color", text="", emboss=True)
+ split.prop(gpl, "info", text="", emboss=False)
- layout.operator("gpencil.palettecolor_select", icon='COLOR', text="Select Strokes")
- layout.operator("gpencil.stroke_change_color", icon='MAN_TRANS', text="Move to Color")
+ row = layout.row(align=True)
+ # row.prop(gpl, "lock", text="", emboss=False)
+ row.prop(gpl, "hide", text="", emboss=False)
+ elif self.layout_type == 'GRID':
+ layout.alignment = 'CENTER'
+ layout.label(text="", icon_value=icon)
class GreasePencilDataPanel:
- # subclass must set
- # bl_space_type = 'IMAGE_EDITOR'
- bl_label = "Grease Pencil Layers"
+ bl_label = "Annotations"
bl_region_type = 'UI'
+ @classmethod
+ def poll(cls, context):
+ # Show this panel as long as someone that might own this exists
+ # AND the owner isn't an object (e.g. GP Object)
+ if context.gpencil_data_owner is None:
+ return False
+ elif type(context.gpencil_data_owner) is bpy.types.Object:
+ return False
+ else:
+ return True
+
@staticmethod
def draw_header(self, context):
- self.layout.prop(context.space_data, "show_grease_pencil", text="")
+ if context.space_data.type != 'VIEW_3D':
+ self.layout.prop(context.space_data, "show_annotation", text="")
@staticmethod
def draw(self, context):
layout = self.layout
+ #layout.use_property_split = True
+ layout.use_property_decorate = False
# owner of Grease Pencil data
gpd_owner = context.gpencil_data_owner
gpd = context.gpencil_data
# Owner Selector
- if context.space_data.type == 'VIEW_3D':
- layout.row().prop(context.tool_settings, "grease_pencil_source", expand=True)
- elif context.space_data.type == 'CLIP_EDITOR':
+ if context.space_data.type == 'CLIP_EDITOR':
layout.row().prop(context.space_data, "grease_pencil_source", expand=True)
-
# Grease Pencil data selector
layout.template_ID(gpd_owner, "grease_pencil", new="gpencil.data_add", unlink="gpencil.data_unlink")
# Grease Pencil data...
if (gpd is None) or (not gpd.layers):
- layout.operator("gpencil.layer_add", text="New Layer")
+ layout.operator("gpencil.layer_add", text="New Note")
else:
self.draw_layers(context, layout, gpd)
@@ -926,7 +746,7 @@ class GreasePencilDataPanel:
layer_rows = 5
else:
layer_rows = 2
- col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index", rows=layer_rows)
+ col.template_list("GPENCIL_UL_annotation_layer", "", gpd, "layers", gpd.layers, "active_index", rows=layer_rows)
col = row.column()
@@ -936,8 +756,6 @@ class GreasePencilDataPanel:
gpl = context.active_gpencil_layer
if gpl:
- sub.menu("GPENCIL_MT_layer_specials", icon='DOWNARROW_HLT', text="")
-
if len(gpd.layers) > 1:
col.separator()
@@ -945,203 +763,70 @@ class GreasePencilDataPanel:
sub.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
sub.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
- col.separator()
-
- sub = col.column(align=True)
- sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
- sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True
-
if gpl:
- self.draw_layer(context, layout, gpl)
-
- def draw_layer(self, context, layout, gpl):
- row = layout.row(align=True)
- row.prop(gpl, "opacity", text="Opacity", slider=True)
-
- # Layer options
- split = layout.split(percentage=0.5)
- split.active = not gpl.lock
- split.prop(gpl, "show_x_ray")
- split.prop(gpl, "show_points")
-
- # Offsets + Parenting (where available)
- if context.space_data.type == 'VIEW_3D':
- split = layout.split(percentage=0.5)
- else:
- split = layout.column() # parenting is not available in 2D editors...
- split.active = not gpl.lock
-
- # Offsets - Color Tint
- col = split.column()
- subcol = col.column(align=True)
- subcol.label("Tint")
- subcol.enabled = not gpl.lock
- subcol.prop(gpl, "tint_color", text="")
- subcol.prop(gpl, "tint_factor", text="Factor", slider=True)
-
- # Offsets - Thickness
- row = col.row(align=True)
- row.prop(gpl, "line_change", text="Thickness Change", slider=True)
- row.operator("gpencil.stroke_apply_thickness", icon='STYLUS_PRESSURE', text="")
+ # layout.prop(gpl, "opacity", text="Opacity", slider=True)
+ # layout.prop(gpl, "thickness", text="Thickness")
+ #
+ # layout.separator()
- # Parenting
- if context.space_data.type == 'VIEW_3D':
- col = split.column(align=True)
- col.label(text="Parent:")
- col.prop(gpl, "parent", text="")
+ # Full-Row - Frame Locking (and Delete Frame)
+ row = layout.row(align=True)
+ row.active = not gpl.lock
- sub = col.column()
- sub.prop(gpl, "parent_type", text="")
- parent = gpl.parent
- if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE':
- sub.prop_search(gpl, "parent_bone", parent.data, "bones", text="")
+ if gpl.active_frame:
+ lock_status = iface_("Locked") if gpl.lock_frame else iface_("Unlocked")
+ lock_label = iface_("Frame: %d (%s)") % (gpl.active_frame.frame_number, lock_status)
+ else:
+ lock_label = iface_("Lock Frame")
+ row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED')
+ row.operator("gpencil.active_frame_delete", text="", icon='X')
- layout.separator()
- # Full-Row - Frame Locking (and Delete Frame)
- row = layout.row(align=True)
- row.active = not gpl.lock
- if gpl.active_frame:
- lock_status = iface_("Locked") if gpl.lock_frame else iface_("Unlocked")
- lock_label = iface_("Frame: %d (%s)") % (gpl.active_frame.frame_number, lock_status)
- else:
- lock_label = iface_("Lock Frame")
- row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED')
- row.operator("gpencil.active_frame_delete", text="", icon='X')
-
- layout.separator()
+class GreasePencilOnionPanel:
+ @staticmethod
+ def draw_settings(layout, gp):
+ col = layout.column()
- # Onion skinning
- col = layout.column(align=True)
- col.active = not gpl.lock
+ col.prop(gp, "onion_mode")
row = col.row()
- row.prop(gpl, "use_onion_skinning")
- sub = row.row(align=True)
- icon = 'RESTRICT_RENDER_OFF' if gpl.use_ghosts_always else 'RESTRICT_RENDER_ON'
- sub.prop(gpl, "use_ghosts_always", text="", icon=icon)
- sub.prop(gpl, "use_ghost_custom_colors", text="", icon='COLOR')
-
- split = col.split(percentage=0.5)
- split.active = gpl.use_onion_skinning
+ row.prop(gp, "onion_factor", text="Opacity", slider=True)
# - Before Frames
- sub = split.column(align=True)
+ sub = layout.column(align=True)
row = sub.row(align=True)
- row.active = gpl.use_ghost_custom_colors
- row.prop(gpl, "before_color", text="")
- sub.prop(gpl, "ghost_before_range", text="Before")
+ row.active = gp.use_ghost_custom_colors
+ row.prop(gp, "before_color", text="Color Before")
- # - After Frames
- sub = split.column(align=True)
row = sub.row(align=True)
- row.active = gpl.use_ghost_custom_colors
- row.prop(gpl, "after_color", text="")
- sub.prop(gpl, "ghost_after_range", text="After")
-
-
-class GreasePencilPaletteColorPanel:
- # subclass must set
- bl_label = "Grease Pencil Colors"
- bl_region_type = 'UI'
-
- @classmethod
- def poll(cls, context):
- # XXX - disabled in 2.8 branch.
- return False
-
- if context.gpencil_data is None:
- return False
-
- gpd = context.gpencil_data
- return bool(gpd.layers.active)
-
- @staticmethod
- def draw(self, context):
- layout = self.layout
- palette = context.active_gpencil_palette
+ row.active = gp.onion_mode in ('ABSOLUTE', 'RELATIVE')
+ row.prop(gp, "ghost_before_range", text="Frames Before")
- if palette:
- row = layout.row(align=True)
- row.operator_context = 'EXEC_REGION_WIN'
- row.operator_menu_enum("gpencil.palette_change", "palette", text="", icon='COLOR')
- row.prop(palette, "name", text="")
- row.operator("gpencil.palette_add", icon='ZOOMIN', text="")
- row.operator("gpencil.palette_remove", icon='X', text="")
-
- # Palette colors
- row = layout.row()
- col = row.column()
- if len(palette.colors) >= 2:
- color_rows = 5
- else:
- color_rows = 2
- col.template_list("GPENCIL_UL_palettecolor", "", palette, "colors", palette.colors, "active_index",
- rows=color_rows)
-
- col = row.column()
+ # - After Frames
+ sub = layout.column(align=True)
+ row = sub.row(align=True)
+ row.active = gp.use_ghost_custom_colors
+ row.prop(gp, "after_color", text="Color After")
- sub = col.column(align=True)
- sub.operator("gpencil.palettecolor_add", icon='ZOOMIN', text="")
- sub.operator("gpencil.palettecolor_remove", icon='ZOOMOUT', text="")
+ row = sub.row(align=True)
+ row.active = gp.onion_mode in ('ABSOLUTE', 'RELATIVE')
+ row.prop(gp, "ghost_after_range", text="Frames After")
- palcol = context.active_gpencil_palettecolor
- if palcol:
- sub.menu("GPENCIL_MT_palettecolor_specials", icon='DOWNARROW_HLT', text="")
+ layout.prop(gp, "use_ghost_custom_colors", text="Use Custom Color")
+ layout.prop(gp, "use_ghosts_always", text="View In Render")
- if len(palette.colors) > 1:
- col.separator()
+ # - fade and loop
+ row = layout.row()
+ row.active = gp.use_onion_skinning
+ row.prop(gp, "use_onion_fade", text="Fade")
+ if hasattr(gp, "use_onion_loop"): # XXX
+ subrow = layout.row()
+ subrow.active = gp.onion_mode in ('RELATIVE', 'SELECTED')
+ subrow.prop(gp, "use_onion_loop", text="Loop")
- sub = col.column(align=True)
- sub.operator("gpencil.palettecolor_move", icon='TRIA_UP', text="").direction = 'UP'
- sub.operator("gpencil.palettecolor_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
-
- row = layout.row()
- sub = row.row(align=True)
- sub.label(text="Isolate:") # based on active color only
- sub.operator("gpencil.palettecolor_isolate", icon='LOCKED', text="").affect_visibility = False
- sub.operator("gpencil.palettecolor_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True
- sub = row.row(align=True)
- sub.label(text="Lock:") # based on other stuff...
- sub.operator("gpencil.stroke_lock_color", icon='BORDER_RECT', text="")
- sub.operator("gpencil.palette_lock_layer", icon='COLOR', text="")
-
- pcolor = palette.colors.active
- if pcolor:
- self.draw_palettecolors(layout, pcolor)
-
- # Draw palette colors
- def draw_palettecolors(self, layout, pcolor):
- # color settings
- split = layout.split(percentage=0.5)
- split.active = not pcolor.lock
-
- # Column 1 - Stroke
- col = split.column(align=True)
- col.enabled = not pcolor.lock
- col.label(text="Stroke:")
- col.prop(pcolor, "color", text="")
- col.prop(pcolor, "alpha", slider=True)
-
- # Column 2 - Fill
- col = split.column(align=True)
- col.enabled = not pcolor.lock
- col.label(text="Fill:")
- col.prop(pcolor, "fill_color", text="")
- col.prop(pcolor, "fill_alpha", text="Opacity", slider=True)
-
- # Options
- split = layout.split(percentage=0.5)
- split.active = not pcolor.lock
-
- col = split.column(align=True)
- col.active = not pcolor.lock
- col.prop(pcolor, "use_volumetric_strokes")
- col = split.column(align=True)
- col.active = not pcolor.lock
- col.prop(pcolor, "use_hq_fill")
+###############################
class GreasePencilToolsPanel:
# For use in "2D" Editors without their own toolbar
@@ -1150,6 +835,7 @@ class GreasePencilToolsPanel:
# bl_options = {'DEFAULT_CLOSED'}
bl_label = "Grease Pencil Settings"
bl_region_type = 'UI'
+ bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
@@ -1183,20 +869,23 @@ class GreasePencilToolsPanel:
gpencil_stroke_placement_settings(context, layout)
+###############################
classes = (
GPENCIL_MT_pie_tool_palette,
GPENCIL_MT_pie_settings_palette,
GPENCIL_MT_pie_tools_more,
GPENCIL_MT_pie_sculpt,
+
GPENCIL_MT_snap,
+ GPENCIL_MT_separate,
+
GPENCIL_MT_gpencil_edit_specials,
- GPENCIL_UL_brush,
- GPENCIL_UL_palettecolor,
- GPENCIL_UL_layer,
- GPENCIL_MT_layer_specials,
- GPENCIL_MT_brush_specials,
- GPENCIL_MT_palettecolor_specials,
+ GPENCIL_MT_gpencil_sculpt_specials,
+ GPENCIL_MT_gpencil_draw_specials,
+ GPENCIL_MT_gpencil_draw_delete,
+
+ GPENCIL_UL_annotation_layer,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py
index 0e3e50b3497..5d12f762073 100644
--- a/release/scripts/startup/bl_ui/properties_material.py
+++ b/release/scripts/startup/bl_ui/properties_material.py
@@ -86,8 +86,11 @@ class EEVEE_MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
@classmethod
def poll(cls, context):
- engine = context.engine
- return (context.material or context.object) and (engine in cls.COMPAT_ENGINES)
+ if context.active_object and context.active_object.type == 'GPENCIL':
+ return False
+ else:
+ engine = context.engine
+ return (context.material or context.object) and (engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/properties_material_gpencil.py b/release/scripts/startup/bl_ui/properties_material_gpencil.py
new file mode 100644
index 00000000000..2d823594547
--- /dev/null
+++ b/release/scripts/startup/bl_ui/properties_material_gpencil.py
@@ -0,0 +1,322 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+import bpy
+from bpy.types import Menu, Panel, UIList
+from rna_prop_ui import PropertyPanel
+
+
+class GPENCIL_MT_color_specials(Menu):
+ bl_label = "Layer"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("gpencil.color_reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
+ layout.operator("gpencil.color_hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True
+
+ layout.separator()
+
+ layout.operator("gpencil.color_lock_all", icon='LOCKED', text="Lock All")
+ layout.operator("gpencil.color_unlock_all", icon='UNLOCKED', text="UnLock All")
+
+ layout.separator()
+
+ layout.operator("gpencil.stroke_lock_color", icon='BORDER_RECT', text="Lock Unselected")
+ layout.operator("gpencil.lock_layer", icon='COLOR', text="Lock Unused")
+
+
+class GPENCIL_UL_matslots(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ slot = item
+ ma = slot.material
+ if (ma is not None) and (ma.grease_pencil is not None):
+ gpcolor = ma.grease_pencil
+
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ if gpcolor.lock:
+ layout.active = False
+
+ row = layout.row(align=True)
+ row.enabled = not gpcolor.lock
+ row.prop(ma, "name", text="", emboss=False, icon_value=icon)
+
+ row = layout.row(align=True)
+ row.prop(gpcolor, "lock", text="", emboss=False)
+ row.prop(gpcolor, "hide", text="", emboss=False)
+ if gpcolor.ghost is True:
+ icon = 'GHOST_DISABLED'
+ else:
+ icon = 'GHOST_ENABLED'
+ row.prop(gpcolor, "ghost", text="", icon=icon, emboss=False)
+
+ elif self.layout_type == 'GRID':
+ layout.alignment = 'CENTER'
+ layout.label(text="", icon_value=icon)
+
+
+class GPMaterialButtonsPanel:
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "material"
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return (ob and ob.type == 'GPENCIL' and
+ ob.active_material and
+ ob.active_material.grease_pencil)
+
+
+
+class MATERIAL_PT_gpencil_slots(Panel):
+ bl_label = "Grease Pencil Material Slots"
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "material"
+ bl_options = {'HIDE_HEADER'}
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return ob and ob.type == 'GPENCIL'
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ gpd = context.gpencil_data
+
+ mat = context.object.active_material
+ ob = context.object
+ slot = context.material_slot
+ space = context.space_data
+
+ if ob:
+ is_sortable = len(ob.material_slots) > 1
+ rows = 1
+ if (is_sortable):
+ rows = 4
+
+ row = layout.row()
+
+ row.template_list("GPENCIL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows)
+
+ col = row.column(align=True)
+ col.operator("object.material_slot_add", icon='ZOOMIN', text="")
+ col.operator("object.material_slot_remove", icon='ZOOMOUT', text="")
+
+ col.menu("GPENCIL_MT_color_specials", icon='DOWNARROW_HLT', text="")
+
+ if is_sortable:
+ col.separator()
+
+ col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP'
+ col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+
+ col.separator()
+
+ sub = col.column(align=True)
+ sub.operator("gpencil.color_isolate", icon='LOCKED', text="").affect_visibility = False
+ sub.operator("gpencil.color_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True
+
+ row = layout.row()
+
+ if ob:
+ row.template_ID(ob, "active_material", new="material.new", live_icon=True)
+
+ if slot:
+ icon_link = 'MESH_DATA' if slot.link == 'DATA' else 'OBJECT_DATA'
+ row.prop(slot, "link", icon=icon_link, icon_only=True)
+
+ if gpd.use_stroke_edit_mode:
+ row = layout.row(align=True)
+ row.operator("gpencil.stroke_change_color", text="Assign")
+ row.operator("gpencil.color_select", text="Select")
+
+ elif mat:
+ row.template_ID(space, "pin_id")
+
+
+# Used as parent for "Stroke" and "Fill" panels
+class MATERIAL_PT_gpencil_surface(GPMaterialButtonsPanel, Panel):
+ bl_label = "Surface"
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ ma = context.object.active_material
+ if ma is None or ma.grease_pencil is None:
+ return False
+
+ return ob and ob.type == 'GPENCIL'
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+
+class MATERIAL_PT_gpencil_strokecolor(GPMaterialButtonsPanel, Panel):
+ bl_label = "Stroke"
+ bl_parent_id = 'MATERIAL_PT_gpencil_surface'
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ ma = context.object.active_material
+ if ma is not None and ma.grease_pencil is not None:
+ gpcolor = ma.grease_pencil
+
+ col = layout.column()
+ col.active = not gpcolor.lock
+
+ col.prop(gpcolor, "mode")
+
+ col.prop(gpcolor, "stroke_style", text="Style")
+
+ if gpcolor.stroke_style == 'TEXTURE':
+ row = col.row()
+ row.enabled = not gpcolor.lock
+ col = row.column(align=True)
+ col.template_ID(gpcolor, "stroke_image", open="image.open")
+ col.prop(gpcolor, "pixel_size", text="UV Factor")
+ col.prop(gpcolor, "use_stroke_pattern", text="Use As Pattern")
+
+ if gpcolor.stroke_style == 'SOLID' or gpcolor.use_stroke_pattern is True:
+ col.prop(gpcolor, "color", text="Color")
+
+
+class MATERIAL_PT_gpencil_fillcolor(GPMaterialButtonsPanel, Panel):
+ bl_label = "Fill"
+ bl_parent_id = 'MATERIAL_PT_gpencil_surface'
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ ma = context.object.active_material
+ if ma is not None and ma.grease_pencil:
+ gpcolor = ma.grease_pencil
+
+ # color settings
+ col = layout.column()
+ col.active = not gpcolor.lock
+ col.prop(gpcolor, "fill_style", text="Style")
+
+ if gpcolor.fill_style == 'GRADIENT':
+ col.prop(gpcolor, "gradient_type")
+
+ if gpcolor.fill_style != 'TEXTURE':
+ col.prop(gpcolor, "fill_color", text="Color")
+
+ if gpcolor.fill_style in ('GRADIENT', 'CHESSBOARD'):
+ col.prop(gpcolor, "mix_color", text="Secondary Color")
+
+ if gpcolor.fill_style == 'GRADIENT':
+ col.prop(gpcolor, "mix_factor", text="Mix Factor", slider=True)
+
+ if gpcolor.fill_style in ('GRADIENT', 'CHESSBOARD'):
+ col.prop(gpcolor, "flip", text="Flip Colors")
+
+ col.prop(gpcolor, "pattern_shift", text="Location")
+ col.prop(gpcolor, "pattern_scale", text="Scale")
+
+ if gpcolor.gradient_type == 'RADIAL' and gpcolor.fill_style not in ('SOLID', 'CHESSBOARD'):
+ col.prop(gpcolor, "pattern_radius", text="Radius")
+ else:
+ if gpcolor.fill_style != 'SOLID':
+ col.prop(gpcolor, "pattern_angle", text="Angle")
+
+ if gpcolor.fill_style == 'CHESSBOARD':
+ col.prop(gpcolor, "pattern_gridsize", text="Box Size")
+
+ # Texture
+ if gpcolor.fill_style == 'TEXTURE' or (gpcolor.texture_mix is True and gpcolor.fill_style == 'SOLID'):
+ col.template_ID(gpcolor, "fill_image", open="image.open")
+
+ if gpcolor.fill_style == 'TEXTURE':
+ col.prop(gpcolor, "use_fill_pattern", text="Use As Pattern")
+ if gpcolor.use_fill_pattern is True:
+ col.prop(gpcolor, "fill_color", text="Color")
+
+ col.prop(gpcolor, "texture_offset", text="Offset")
+ col.prop(gpcolor, "texture_scale", text="Scale")
+ col.prop(gpcolor, "texture_angle")
+ col.prop(gpcolor, "texture_opacity")
+ col.prop(gpcolor, "texture_clamp", text="Clip Image")
+
+ if gpcolor.use_fill_pattern is False:
+ col.prop(gpcolor, "texture_mix", text="Mix With Color")
+
+ if gpcolor.texture_mix is True:
+ col.prop(gpcolor, "fill_color", text="Mix Color")
+ col.prop(gpcolor, "mix_factor", text="Mix Factor", slider=True)
+
+
+class MATERIAL_PT_gpencil_preview(GPMaterialButtonsPanel, Panel):
+ bl_label = "Preview"
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ ma = context.object.active_material
+ self.layout.label(ma.name)
+ self.layout.template_preview(ma)
+
+
+class MATERIAL_PT_gpencil_custom_props(GPMaterialButtonsPanel, PropertyPanel, Panel):
+ COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_OPENGL'}
+ _context_path = "object.active_material"
+ _property_type = bpy.types.Material
+
+
+class MATERIAL_PT_gpencil_options(GPMaterialButtonsPanel, Panel):
+ bl_label = "Options"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ ma = context.object.active_material
+ if ma is not None and ma.grease_pencil is not None:
+ gpcolor = ma.grease_pencil
+ layout.prop(gpcolor, "pass_index")
+
+
+classes = (
+ GPENCIL_UL_matslots,
+ GPENCIL_MT_color_specials,
+ MATERIAL_PT_gpencil_slots,
+ MATERIAL_PT_gpencil_preview,
+ MATERIAL_PT_gpencil_surface,
+ MATERIAL_PT_gpencil_strokecolor,
+ MATERIAL_PT_gpencil_fillcolor,
+ MATERIAL_PT_gpencil_options,
+ MATERIAL_PT_gpencil_custom_props,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index 38bfc6ad294..91be9bb5d0a 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -28,9 +28,9 @@ from rna_prop_ui import PropertyPanel
from bl_operators.presets import PresetMenu
from .properties_physics_common import (
- point_cache_ui,
- effector_weights_ui,
-)
+ point_cache_ui,
+ effector_weights_ui,
+ )
class SCENE_PT_units_length_presets(PresetMenu):
@@ -104,7 +104,6 @@ class SCENE_PT_unit(SceneButtonsPanel, Panel):
col.prop(unit, "scale_length")
col.prop(unit, "use_separate")
-
class SceneKeyingSetsPanel:
@staticmethod
@@ -568,6 +567,33 @@ class SCENE_PT_simplify_render(SceneButtonsPanel, Panel):
col.prop(rd, "simplify_child_particles_render", text="Max Child Particles")
+class SCENE_PT_simplify_greasepencil(SceneButtonsPanel, Panel):
+ bl_label = "Simplify Grease Pencil"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw_header(self, context):
+ rd = context.scene.render
+ self.layout.prop(rd, "simplify_gpencil", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ rd = context.scene.render
+
+ layout.active = rd.simplify_gpencil
+
+ row = layout.row()
+ row.prop(rd, "simplify_gpencil_onplay", text="Only on Play")
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(rd, "simplify_gpencil_view_fill", text="Fill")
+ col.prop(rd, "simplify_gpencil_remove_lines", text="Remove Fill Lines")
+ col.prop(rd, "simplify_gpencil_view_modifier", text="Modifiers")
+
+
class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
_context_path = "scene"
@@ -593,6 +619,7 @@ classes = (
SCENE_PT_simplify,
SCENE_PT_simplify_viewport,
SCENE_PT_simplify_render,
+ SCENE_PT_simplify_greasepencil,
SCENE_PT_custom_props,
)
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index 23c3e97ac9a..8e32d98529b 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -23,14 +23,8 @@ from bpy.types import Panel, Header, Menu, UIList
from bpy.app.translations import pgettext_iface as iface_
from bl_operators.presets import PresetMenu
from .properties_grease_pencil_common import (
- GreasePencilDrawingToolsPanel,
- GreasePencilStrokeEditPanel,
- GreasePencilStrokeSculptPanel,
- GreasePencilBrushPanel,
- GreasePencilBrushCurvesPanel,
- GreasePencilDataPanel,
- GreasePencilPaletteColorPanel,
-)
+ GreasePencilDrawingToolsPanel,
+ GreasePencilDataPanel)
class CLIP_UL_tracking_objects(UIList):
@@ -1154,40 +1148,12 @@ class CLIP_PT_grease_pencil(GreasePencilDataPanel, CLIP_PT_clip_view_panel, Pane
# But, this should only be visible in "clip" view
-# Grease Pencil palette colors
-class CLIP_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, CLIP_PT_clip_view_panel, Panel):
- bl_space_type = 'CLIP_EDITOR'
- bl_region_type = 'UI'
- bl_options = {'DEFAULT_CLOSED'}
-
- # NOTE: this is just a wrapper around the generic GP Panel
- # But, this should only be visible in "clip" view
-
-
# Grease Pencil drawing tools
class CLIP_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
bl_space_type = 'CLIP_EDITOR'
+ bl_region_type = 'TOOLS'
-# Grease Pencil stroke editing tools
-class CLIP_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
- bl_space_type = 'CLIP_EDITOR'
-
-
-# Grease Pencil stroke sculpting tools
-class CLIP_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
- bl_space_type = 'CLIP_EDITOR'
-
-
-# Grease Pencil drawing brushes
-class CLIP_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
- bl_space_type = 'CLIP_EDITOR'
-
-
-# Grease Pencil drawing curves
-class CLIP_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
- bl_space_type = 'CLIP_EDITOR'
-
class CLIP_MT_view(Menu):
bl_label = "View"
@@ -1515,12 +1481,7 @@ classes = (
CLIP_PT_footage_info,
CLIP_PT_tools_scenesetup,
CLIP_PT_grease_pencil,
- CLIP_PT_grease_pencil_palettecolor,
CLIP_PT_tools_grease_pencil_draw,
- CLIP_PT_tools_grease_pencil_edit,
- CLIP_PT_tools_grease_pencil_sculpt,
- CLIP_PT_tools_grease_pencil_brush,
- CLIP_PT_tools_grease_pencil_brushcurves,
CLIP_MT_view,
CLIP_MT_clip,
CLIP_MT_proxy,
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index 1303e46ab6c..501f58e9901 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -21,20 +21,15 @@ import bpy
import math
from bpy.types import Header, Menu, Panel, UIList
from .properties_paint_common import (
- UnifiedPaintPanel,
- brush_texture_settings,
- brush_texpaint_common,
- brush_mask_texture_settings,
-)
+ UnifiedPaintPanel,
+ brush_texture_settings,
+ brush_texpaint_common,
+ brush_mask_texture_settings,
+ )
from .properties_grease_pencil_common import (
- GreasePencilDrawingToolsPanel,
- GreasePencilStrokeEditPanel,
- GreasePencilStrokeSculptPanel,
- GreasePencilBrushPanel,
- GreasePencilBrushCurvesPanel,
- GreasePencilDataPanel,
- GreasePencilPaletteColorPanel,
-)
+ GreasePencilDrawingToolsPanel,
+ GreasePencilDataPanel
+ )
from bpy.app.translations import pgettext_iface as iface_
@@ -1346,39 +1341,12 @@ class IMAGE_PT_grease_pencil(GreasePencilDataPanel, Panel):
# NOTE: this is just a wrapper around the generic GP Panel
-
-# Grease Pencil palette colors
-class IMAGE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
- bl_space_type = 'IMAGE_EDITOR'
- bl_region_type = 'UI'
-
- # NOTE: this is just a wrapper around the generic GP Panel
-
-
# Grease Pencil drawing tools
class IMAGE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
bl_space_type = 'IMAGE_EDITOR'
+ bl_region_type = 'TOOLS'
-# Grease Pencil stroke editing tools
-class IMAGE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
- bl_space_type = 'IMAGE_EDITOR'
-
-
-# Grease Pencil stroke sculpting tools
-class IMAGE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
- bl_space_type = 'IMAGE_EDITOR'
-
-
-# Grease Pencil drawing brushes
-class IMAGE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
- bl_space_type = 'IMAGE_EDITOR'
-
-
-# Grease Pencil drawing curves
-class IMAGE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
- bl_space_type = 'IMAGE_EDITOR'
-
classes = (
IMAGE_MT_view,
@@ -1430,12 +1398,7 @@ classes = (
IMAGE_PT_sample_line,
IMAGE_PT_scope_sample,
IMAGE_PT_grease_pencil,
- IMAGE_PT_grease_pencil_palettecolor,
IMAGE_PT_tools_grease_pencil_draw,
- IMAGE_PT_tools_grease_pencil_edit,
- IMAGE_PT_tools_grease_pencil_sculpt,
- IMAGE_PT_tools_grease_pencil_brush,
- IMAGE_PT_tools_grease_pencil_brushcurves,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 45343c09b27..affbf70b1a0 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -23,15 +23,10 @@ from bpy.types import Header, Menu, Panel
from bpy.app.translations import pgettext_iface as iface_
from bl_operators.presets import PresetMenu
from .properties_grease_pencil_common import (
- GreasePencilDrawingToolsPanel,
- GreasePencilStrokeEditPanel,
- GreasePencilStrokeSculptPanel,
- GreasePencilBrushPanel,
- GreasePencilBrushCurvesPanel,
- GreasePencilDataPanel,
- GreasePencilPaletteColorPanel,
- GreasePencilToolsPanel
-)
+ GreasePencilDrawingToolsPanel,
+ GreasePencilDataPanel,
+ GreasePencilToolsPanel
+ )
class NODE_HT_header(Header):
@@ -539,19 +534,6 @@ class NODE_PT_grease_pencil(GreasePencilDataPanel, Panel):
return snode is not None and snode.node_tree is not None
-# Grease Pencil palette colors
-class NODE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
- bl_space_type = 'NODE_EDITOR'
- bl_region_type = 'UI'
-
- # NOTE: this is just a wrapper around the generic GP Panel
-
- @classmethod
- def poll(cls, context):
- snode = context.space_data
- return snode is not None and snode.node_tree is not None
-
-
class NODE_PT_grease_pencil_tools(GreasePencilToolsPanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
@@ -571,31 +553,6 @@ class NODE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
bl_region_type = 'TOOLS'
-# Grease Pencil stroke editing tools
-class NODE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
- bl_space_type = 'NODE_EDITOR'
- bl_region_type = 'TOOLS'
-
-
-# Grease Pencil stroke sculpting tools
-class NODE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
- bl_space_type = 'NODE_EDITOR'
- bl_region_type = 'TOOLS'
-
-# Grease Pencil drawing brushes
-
-
-class NODE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
- bl_space_type = 'NODE_EDITOR'
- bl_region_type = 'TOOLS'
-
-# Grease Pencil drawing curves
-
-
-class NODE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
- bl_space_type = 'NODE_EDITOR'
- bl_region_type = 'TOOLS'
-
# -----------------------------
@@ -620,13 +577,8 @@ classes = (
NODE_PT_quality,
NODE_UL_interface_sockets,
NODE_PT_grease_pencil,
- NODE_PT_grease_pencil_palettecolor,
NODE_PT_grease_pencil_tools,
NODE_PT_tools_grease_pencil_draw,
- NODE_PT_tools_grease_pencil_edit,
- NODE_PT_tools_grease_pencil_sculpt,
- NODE_PT_tools_grease_pencil_brush,
- NODE_PT_tools_grease_pencil_brushcurves,
)
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index bac462dcbab..84ae59772b6 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -22,7 +22,6 @@ from bpy.types import Header, Menu, Panel
from rna_prop_ui import PropertyPanel
from .properties_grease_pencil_common import (
GreasePencilDataPanel,
- GreasePencilPaletteColorPanel,
GreasePencilToolsPanel,
)
from bpy.app.translations import pgettext_iface as iface_
@@ -1281,14 +1280,6 @@ class SEQUENCER_PT_grease_pencil(GreasePencilDataPanel, SequencerButtonsPanel_Ou
# But, it should only show up when there are images in the preview region
-class SEQUENCER_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, SequencerButtonsPanel_Output, Panel):
- bl_space_type = 'SEQUENCE_EDITOR'
- bl_region_type = 'UI'
-
- # NOTE: this is just a wrapper around the generic GP Panel
- # But, it should only show up when there are images in the preview region
-
-
class SEQUENCER_PT_grease_pencil_tools(GreasePencilToolsPanel, SequencerButtonsPanel_Output, Panel):
bl_space_type = 'SEQUENCE_EDITOR'
bl_region_type = 'UI'
@@ -1333,7 +1324,6 @@ classes = (
SEQUENCER_PT_view_safe_areas,
SEQUENCER_PT_modifiers,
SEQUENCER_PT_grease_pencil,
- SEQUENCER_PT_grease_pencil_palettecolor,
SEQUENCER_PT_grease_pencil_tools,
SEQUENCER_PT_custom_props,
)
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 3101ffc8336..b682588629b 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -24,6 +24,7 @@
# For now keep this in a single file since it's an area that may change,
# so avoid making changes all over the place.
+import bpy
from bpy.types import Panel
from .space_toolsystem_common import (
@@ -39,21 +40,77 @@ def generate_from_brushes_ex(
brush_category_attr,
brush_category_layout,
):
+ def draw_settings(context, layout, tool):
+ _defs_gpencil_paint.draw_settings_common(context, layout, tool)
+
# Categories
brush_categories = {}
- for brush in context.blend_data.brushes:
- if getattr(brush, brush_test_attr):
- category = getattr(brush, brush_category_attr)
- name = brush.name
- brush_categories.setdefault(category, []).append(
- ToolDef.from_dict(
- dict(
- text=name,
- icon=icon_prefix + category.lower(),
- data_block=name,
+ if context.mode != 'GPENCIL_PAINT':
+ for brush in context.blend_data.brushes:
+ if getattr(brush, brush_test_attr) and brush.gpencil_settings is None:
+ category = getattr(brush, brush_category_attr)
+ name = brush.name
+ brush_categories.setdefault(category, []).append(
+ ToolDef.from_dict(
+ dict(
+ text=name,
+ icon=icon_prefix + category.lower(),
+ data_block=name,
+ )
)
)
- )
+ else:
+ for brush_type in brush_category_layout:
+ for brush in context.blend_data.brushes:
+ if getattr(brush, brush_test_attr) and brush.gpencil_settings.gp_icon == brush_type[0]:
+ category = brush_type[0]
+ name = brush.name
+
+ # rename default brushes for tool bar
+ if name.startswith("Draw "):
+ text = name.replace("Draw ", "")
+ elif name.startswith("Eraser "):
+ text = name.replace("Eraser ", "")
+ elif name.startswith("Fill "):
+ text = name.replace(" Area", "")
+ else:
+ text = name
+
+ # define icon
+ gp_icon = brush.gpencil_settings.gp_icon
+ if gp_icon == 'PENCIL':
+ icon_name = 'draw_pencil'
+ elif gp_icon == 'PEN':
+ icon_name = 'draw_pen'
+ elif gp_icon == 'INK':
+ icon_name = 'draw_ink'
+ elif gp_icon == 'INKNOISE':
+ icon_name = 'draw_noise'
+ elif gp_icon == 'BLOCK':
+ icon_name = 'draw_block'
+ elif gp_icon == 'MARKER':
+ icon_name = 'draw_marker'
+ elif gp_icon == 'FILL':
+ icon_name = 'draw_fill'
+ elif gp_icon == 'SOFT':
+ icon_name = 'draw.eraser_soft'
+ elif gp_icon == 'HARD':
+ icon_name = 'draw.eraser_hard'
+ elif gp_icon == 'STROKE':
+ icon_name = 'draw.eraser_stroke'
+
+ brush_categories.setdefault(category, []).append(
+ ToolDef.from_dict(
+ dict(
+ text=text,
+ icon=icon_prefix + icon_name,
+ data_block=name,
+ widget=None,
+ operator="gpencil.draw",
+ draw_settings=draw_settings,
+ )
+ )
+ )
def tools_from_brush_group(groups):
assert(type(groups) is tuple)
@@ -61,6 +118,7 @@ def generate_from_brushes_ex(
tool_defs = tuple(brush_categories.pop(groups[0], ()))
else:
tool_defs = tuple(item for g in groups for item in brush_categories.pop(g, ()))
+
if len(tool_defs) > 1:
return (tool_defs,)
else:
@@ -125,6 +183,112 @@ class _defs_view3d_generic:
)
+class _defs_annotate:
+ @classmethod
+ def draw_settings_common(cls, context, layout, tool):
+ user_prefs = context.user_preferences
+ ts = context.tool_settings
+
+ # XXX: These context checks are needed for layer-dependent settings,
+ # but this breaks for using topbar for 2D editor active tools, etc.
+ if type(context.gpencil_data_owner) is bpy.types.Object:
+ gpd = context.scene.grease_pencil
+ else:
+ gpd = context.gpencil_data
+
+ gpl = gpd.layers.active if gpd else None
+
+ if gpd and gpl:
+ layout.prop(gpd.layers, "active_note", text="")
+ layout.prop(gpl, "thickness", text="Thickness")
+ else:
+ layout.prop(user_prefs.edit, "grease_pencil_default_color", text="Color")
+ layout.prop(ts, "annotation_thickness", text="Thickness")
+
+ # For 3D view, show the stroke placement settings
+ # XXX: How to tell what editor the active tool comes from?
+ is_3d_view = True
+ if is_3d_view:
+ layout.separator()
+
+ row = layout.row(align=True)
+ row.prop(ts, "annotation_stroke_placement_view3d", text="Orientation")
+ if ts.gpencil_stroke_placement_view3d == 'CURSOR':
+ row.prop(ts.gpencil_sculpt, "lockaxis")
+ elif ts.gpencil_stroke_placement_view3d in {'SURFACE', 'STROKE'}:
+ row.prop(ts, "use_gpencil_stroke_endpoints")
+
+ @ToolDef.from_fn
+ def scribble():
+ def draw_settings(context, layout, tool):
+ _defs_annotate.draw_settings_common(context, layout, tool)
+
+ return dict(
+ text="Annotate",
+ icon="ops.gpencil.draw",
+ cursor='PAINT_BRUSH',
+ keymap=(
+ ("gpencil.annotate",
+ dict(mode='DRAW', wait_for_input=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def line():
+ def draw_settings(context, layout, tool):
+ _defs_annotate.draw_settings_common(context, layout, tool)
+
+ return dict(
+ text="Draw Line",
+ icon="ops.gpencil.draw.line",
+ cursor='CROSSHAIR',
+ keymap=(
+ ("gpencil.annotate",
+ dict(mode='DRAW_STRAIGHT', wait_for_input=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def poly():
+ def draw_settings(context, layout, tool):
+ _defs_annotate.draw_settings_common(context, layout, tool)
+
+ return dict(
+ text="Draw Polygon",
+ icon="ops.gpencil.draw.poly",
+ cursor='CROSSHAIR',
+ keymap=(
+ ("gpencil.annotate",
+ dict(mode='DRAW_POLY', wait_for_input=False),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def eraser():
+ def draw_settings(context, layout, tool):
+ # TODO: Move this setting to toolsettings
+ user_prefs = context.user_preferences
+ layout.prop(user_prefs.edit, "grease_pencil_eraser_radius", text="Radius")
+
+ return dict(
+ text="Eraser",
+ icon="ops.gpencil.draw.eraser",
+ cursor='CROSSHAIR', # XXX: Always show brush circle when enabled
+ keymap=(
+ ("gpencil.annotate",
+ dict(mode='ERASER', wait_for_input=False),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+
class _defs_transform:
@ToolDef.from_fn
@@ -865,6 +1029,331 @@ class _defs_uv_select:
),
)
+class _defs_gpencil_paint:
+ @classmethod
+ def draw_color_selector(cls, context, layout):
+ brush = context.active_gpencil_brush
+ gp_settings = brush.gpencil_settings
+ ts = context.tool_settings
+ row = layout.row(align=True)
+ row.prop(ts, "use_gpencil_thumbnail_list", text="", icon="IMGDISPLAY")
+ if ts.use_gpencil_thumbnail_list is False:
+ row.template_ID(gp_settings, "material", live_icon=True)
+ else:
+ row.template_greasepencil_color(gp_settings, "material", rows=3, cols=8, scale=0.8)
+
+ @classmethod
+ def draw_settings_common(cls, context, layout, tool):
+ ob = context.active_object
+ if ob and ob.mode == 'GPENCIL_PAINT':
+ brush = context.active_gpencil_brush
+ gp_settings = brush.gpencil_settings
+ tool_settings= context.tool_settings
+
+ if gp_settings.gpencil_brush_type == 'ERASE':
+ row = layout.row()
+ row.prop(brush, "size", text="Radius")
+ elif gp_settings.gpencil_brush_type == 'FILL':
+ row = layout.row()
+ row.prop(gp_settings, "gpencil_fill_leak", text="Leak Size")
+ row.prop(brush, "size", text="Thickness")
+ row.prop(gp_settings, "gpencil_fill_simplyfy_level", text="Simplify")
+
+ _defs_gpencil_paint.draw_color_selector(context, layout)
+
+ row = layout.row(align=True)
+ row.prop(gp_settings, "gpencil_fill_draw_mode", text="")
+ row.prop(gp_settings, "gpencil_fill_show_boundary", text="", icon='GRID')
+
+ else: # bgpsettings.gpencil_brush_type == 'DRAW':
+ row = layout.row(align=True)
+ row.prop(brush, "size", text="Radius")
+ row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE')
+ row = layout.row(align=True)
+ row.prop(gp_settings, "pen_strength", slider=True)
+ row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE')
+
+ _defs_gpencil_paint.draw_color_selector(context, layout)
+
+
+ @staticmethod
+ def generate_from_brushes(context):
+ return generate_from_brushes_ex(
+ context,
+ icon_prefix="brush.gpencil.",
+ brush_test_attr="use_paint_grease_pencil",
+ brush_category_attr="grease_pencil_tool",
+ brush_category_layout=(
+ ('PENCIL',),
+ ('PEN',),
+ ('INK',),
+ ('INKNOISE',),
+ ('BLOCK',),
+ ('MARKER',),
+ ('FILL',),
+ ('SOFT',),
+ ('HARD',),
+ ('STROKE',),
+ )
+ )
+
+
+class _defs_gpencil_edit:
+ @ToolDef.from_fn
+ def bend():
+ return dict(
+ text="Bend",
+ icon="ops.gpencil.edit_bend",
+ widget=None,
+ keymap=(
+ ("transform.bend",
+ dict(),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def mirror():
+ return dict(
+ text="Mirror",
+ icon="ops.gpencil.edit_mirror",
+ widget=None,
+ keymap=(
+ ("transform.mirror",
+ dict(),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def shear():
+ return dict(
+ text="Shear",
+ icon="ops.gpencil.edit_shear",
+ widget=None,
+ keymap=(
+ ("transform.shear",
+ dict(),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def tosphere():
+ return dict(
+ text="To Sphere",
+ icon="ops.gpencil.edit_to_sphere",
+ widget=None,
+ keymap=(
+ ("transform.tosphere",
+ dict(),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ )
+
+
+class _defs_gpencil_sculpt:
+ @classmethod
+ def draw_settings_common(cls, context, layout, tool):
+ ob = context.active_object
+ if ob and ob.mode == 'GPENCIL_SCULPT':
+ ts = context.tool_settings
+ settings = ts.gpencil_sculpt
+ brush = settings.brush
+
+ layout.prop(brush, "size", slider=True)
+
+ row = layout.row(align=True)
+ row.prop(brush, "strength", slider=True)
+ row.prop(brush, "use_pressure_strength", text="")
+ row.separator()
+ row.prop(ts.gpencil_sculpt, "use_select_mask", text="")
+
+ @ToolDef.from_fn
+ def smooth():
+ def draw_settings(context, layout, tool):
+ _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
+
+ return dict(
+ text="Smooth",
+ icon="ops.gpencil.sculpt_smooth",
+ widget=None,
+ keymap=(
+ ("gpencil.brush_paint",
+ dict(mode='SMOOTH', wait_for_input=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def thickness():
+ def draw_settings(context, layout, tool):
+ _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
+
+ return dict(
+ text="Thickness",
+ icon="ops.gpencil.sculpt_thickness",
+ widget=None,
+ keymap=(
+ ("gpencil.brush_paint",
+ dict(mode='THICKNESS', wait_for_input=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def strength():
+ def draw_settings(context, layout, tool):
+ _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
+
+ return dict(
+ text="Strength",
+ icon="ops.gpencil.sculpt_strength",
+ widget=None,
+ keymap=(
+ ("gpencil.brush_paint",
+ dict(mode='STRENGTH', wait_for_input=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def grab():
+ def draw_settings(context, layout, tool):
+ _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
+
+ return dict(
+ text="Grab",
+ icon="ops.gpencil.sculpt_grab",
+ widget=None,
+ keymap=(
+ ("gpencil.brush_paint",
+ dict(mode='GRAB', wait_for_input=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def push():
+ def draw_settings(context, layout, tool):
+ _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
+
+ return dict(
+ text="Push",
+ icon="ops.gpencil.sculpt_push",
+ widget=None,
+ keymap=(
+ ("gpencil.brush_paint",
+ dict(mode='PUSH', wait_for_input=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def twist():
+ def draw_settings(context, layout, tool):
+ _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
+
+ return dict(
+ text="Twist",
+ icon="ops.gpencil.sculpt_twist",
+ widget=None,
+ keymap=(
+ ("gpencil.brush_paint",
+ dict(mode='TWIST', wait_for_input=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def pinch():
+ def draw_settings(context, layout, tool):
+ _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
+
+ return dict(
+ text="Pinch",
+ icon="ops.gpencil.sculpt_pinch",
+ widget=None,
+ keymap=(
+ ("gpencil.brush_paint",
+ dict(mode='PINCH', wait_for_input=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def randomize():
+ def draw_settings(context, layout, tool):
+ _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
+
+ return dict(
+ text="Randomize",
+ icon="ops.gpencil.sculpt_randomize",
+ widget=None,
+ keymap=(
+ ("gpencil.brush_paint",
+ dict(mode='RANDOMIZE', wait_for_input=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def clone():
+ def draw_settings(context, layout, tool):
+ _defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
+
+ return dict(
+ text="Clone",
+ icon="ops.gpencil.sculpt_clone",
+ widget=None,
+ keymap=(
+ ("gpencil.brush_paint",
+ dict(mode='CLONE', wait_for_input=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+
+class _defs_gpencil_weight:
+ @classmethod
+ def draw_settings_common(cls, context, layout, tool):
+ ob = context.active_object
+ if ob and ob.mode == 'GPENCIL_WEIGHT':
+ settings = context.tool_settings.gpencil_sculpt
+ brush = settings.brush
+
+ layout.prop(brush, "size", slider=True)
+
+ row = layout.row(align=True)
+ row.prop(brush, "strength", slider=True)
+ row.prop(brush, "use_pressure_strength", text="")
+
+ @ToolDef.from_fn
+ def paint():
+ def draw_settings(context, layout, tool):
+ _defs_gpencil_weight.draw_settings_common(context, layout, tool)
+
+ return dict(
+ text="Draw",
+ icon="ops.gpencil.sculpt_weight",
+ widget=None,
+ keymap=(
+ ("gpencil.brush_paint",
+ dict(mode='WEIGHT', wait_for_input=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ draw_settings=draw_settings,
+ )
+
class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
bl_space_type = 'IMAGE_EDITOR'
@@ -951,8 +1440,6 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
_defs_transform.scale,
_defs_transform.scale_cage,
),
- None,
- _defs_view3d_generic.ruler,
)
_tools_select = (
@@ -963,6 +1450,16 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
),
)
+ _tools_annotate = (
+ (
+ _defs_annotate.scribble,
+ _defs_annotate.line,
+ _defs_annotate.poly,
+ _defs_annotate.eraser,
+ ),
+ _defs_view3d_generic.ruler,
+ )
+
_tools = {
None: [
_defs_view3d_generic.cursor,
@@ -972,21 +1469,27 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
*_tools_select,
None,
*_tools_transform,
+ None,
+ *_tools_annotate,
],
'POSE': [
*_tools_select,
*_tools_transform,
None,
+ *_tools_annotate,
+ None,
(
_defs_pose.breakdown,
_defs_pose.push,
_defs_pose.relax,
- )
+ ),
],
'EDIT_ARMATURE': [
*_tools_select,
None,
*_tools_transform,
+ None,
+ *_tools_annotate,
_defs_edit_armature.roll,
(
_defs_edit_armature.bone_size,
@@ -996,13 +1499,15 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
(
_defs_edit_armature.extrude,
_defs_edit_armature.extrude_cursor,
- )
+ ),
],
'EDIT_MESH': [
*_tools_select,
None,
*_tools_transform,
None,
+ *_tools_annotate,
+ None,
_defs_edit_mesh.cube_add,
None,
(
@@ -1047,6 +1552,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
*_tools_transform,
None,
+ *_tools_annotate,
+ None,
_defs_edit_curve.draw,
_defs_edit_curve.extrude_cursor,
],
@@ -1075,6 +1582,33 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
_defs_weight_paint.gradient,
],
+ 'GPENCIL_PAINT': [
+ _defs_gpencil_paint.generate_from_brushes,
+ ],
+ 'GPENCIL_EDIT': [
+ *_tools_select,
+ None,
+ *_tools_transform,
+ None,
+ _defs_gpencil_edit.bend,
+ _defs_gpencil_edit.mirror,
+ _defs_gpencil_edit.shear,
+ _defs_gpencil_edit.tosphere,
+ ],
+ 'GPENCIL_SCULPT': [
+ _defs_gpencil_sculpt.smooth,
+ _defs_gpencil_sculpt.thickness,
+ _defs_gpencil_sculpt.strength,
+ _defs_gpencil_sculpt.grab,
+ _defs_gpencil_sculpt.push,
+ _defs_gpencil_sculpt.twist,
+ _defs_gpencil_sculpt.pinch,
+ _defs_gpencil_sculpt.randomize,
+ _defs_gpencil_sculpt.clone,
+ ],
+ 'GPENCIL_WEIGHT': [
+ _defs_gpencil_weight.paint,
+ ],
}
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
index 55129aa0ce1..0d837ae413a 100644
--- a/release/scripts/startup/bl_ui/space_topbar.py
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -128,6 +128,8 @@ class TOPBAR_HT_lower_bar(Header):
pass
elif mode == 'PARTICLE':
layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
+ elif mode == 'GPENCIL_PAINT':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".greasepencil_paint", category="")
def draw_center(self, context):
pass
@@ -165,6 +167,15 @@ class TOPBAR_HT_lower_bar(Header):
layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".particlemode", category="")
elif mode == 'OBJECT':
layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".objectmode", category="")
+ elif mode == 'GPENCIL_PAINT':
+ layout.prop(context.tool_settings, "gpencil_stroke_placement_view3d", text='')
+ if context.tool_settings.gpencil_stroke_placement_view3d in ('ORIGIN', 'CURSOR'):
+ layout.prop(context.tool_settings.gpencil_sculpt, "lockaxis", text='')
+ layout.prop(context.tool_settings, "use_gpencil_draw_onback", text="", icon='ORTHO')
+ layout.prop(context.tool_settings, "use_gpencil_additive_drawing", text="", icon='FREEZE')
+
+ elif mode == 'GPENCIL_SCULPT':
+ layout.prop(context.tool_settings.gpencil_sculpt, "lockaxis", text='')
class _draw_left_context_mode:
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 53aaff7c4bf..52d4640806d 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -361,14 +361,16 @@ class USERPREF_PT_edit(Panel):
row.separator()
col = row.column()
- col.label(text="Grease Pencil:")
+ col.label(text="Annotations:")
+ sub = col.row()
+ sub.prop(edit, "grease_pencil_default_color", text="Default Color")
col.prop(edit, "grease_pencil_eraser_radius", text="Eraser Radius")
col.separator()
+ col.label(text="Grease Pencil/Annotations:")
+ col.separator()
col.prop(edit, "grease_pencil_manhattan_distance", text="Manhattan Distance")
col.prop(edit, "grease_pencil_euclidean_distance", text="Euclidean Distance")
col.separator()
- col.prop(edit, "grease_pencil_default_color", text="Default Color")
- col.separator()
col.prop(edit, "use_grease_pencil_simplify_stroke", text="Simplify Stroke")
col.separator()
col.separator()
@@ -527,7 +529,10 @@ class USERPREF_PT_system(Panel):
col.prop(system, "gpu_viewport_quality")
col.separator()
+ col.label(text="Grease Pencil Options:")
+ col.prop(system, "gpencil_multi_sample", text="")
+ col.separator()
col.label(text="Text Draw Options:")
col.prop(system, "use_text_antialiasing")
if system.use_text_antialiasing:
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index aed5faff73c..eb595e9f12d 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -19,11 +19,8 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
-from .properties_grease_pencil_common import (
- GreasePencilDataPanel,
- GreasePencilPaletteColorPanel,
-)
from .properties_paint_common import UnifiedPaintPanel
+from .properties_grease_pencil_common import GreasePencilDataPanel
from bpy.app.translations import contexts as i18n_contexts
@@ -80,18 +77,40 @@ class VIEW3D_HT_header(Header):
row.operator("pose.paste", text="", icon='PASTEDOWN').flipped = False
row.operator("pose.paste", text="", icon='PASTEFLIPDOWN').flipped = True
- # GPencil
- if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode:
- row = layout.row(align=True)
- row.operator("gpencil.copy", text="", icon='COPYDOWN')
- row.operator("gpencil.paste", text="", icon='PASTEDOWN')
+ # Grease Pencil
+ if obj and obj.type == 'GPENCIL' and context.gpencil_data:
+ gpd = context.gpencil_data
- # XXX: icon
- layout.prop(context.gpencil_data, "use_onion_skinning", text="Onion Skins", icon='PARTICLE_PATH')
+ if gpd.is_stroke_paint_mode:
+ row = layout.row(align=True)
+ row.popover(
+ panel="VIEW3D_PT_tools_grease_pencil_shapes",
+ text="Shapes"
+ )
- row = layout.row(align=True)
- row.prop(tool_settings.gpencil_sculpt, "use_select_mask")
- row.prop(tool_settings.gpencil_sculpt, "selection_alpha", slider=True)
+ if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode or gpd.is_stroke_weight_mode:
+ row = layout.row(align=True)
+ row.prop(gpd, "use_multiedit", text="", icon="FORCE_HARMONIC")
+
+ sub = row.row(align=True)
+ sub.active = gpd.use_multiedit
+ sub.popover(
+ panel="VIEW3D_PT_gpencil_multi_frame",
+ text="Multiframe"
+ )
+
+ if gpd.use_stroke_edit_mode:
+ row = layout.row(align=True)
+ row.operator("gpencil.copy", text="", icon='COPYDOWN')
+ row.operator("gpencil.paste", text="", icon='PASTEDOWN')
+
+ row = layout.row(align=True)
+ row.prop(tool_settings.gpencil_sculpt, "use_select_mask", text="")
+
+ row.popover(
+ panel="VIEW3D_PT_tools_grease_pencil_interpolate",
+ text="Interpolate"
+ )
VIEW3D_MT_editor_menus.draw_collapsible(context, layout)
@@ -101,7 +120,7 @@ class VIEW3D_HT_header(Header):
scene = context.scene
# Orientation
- if object_mode in {'OBJECT', 'EDIT', 'POSE'}:
+ if object_mode in {'OBJECT', 'EDIT', 'POSE', 'GPENCIL_EDIT'}:
orientation = scene.transform_orientation
current_orientation = scene.current_orientation
@@ -126,7 +145,8 @@ class VIEW3D_HT_header(Header):
if obj is None:
show_snap = True
else:
- if object_mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT'}:
+ if object_mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT',
+ 'GPENCIL_PAINT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}:
show_snap = True
else:
@@ -160,13 +180,15 @@ class VIEW3D_HT_header(Header):
# Proportional editing
if obj:
- if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode:
- row = layout.row(align=True)
- row.prop(tool_settings, "proportional_edit", icon_only=True)
+ gpd = context.gpencil_data
+ if gpd is not None:
+ if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode:
+ row = layout.row(align=True)
+ row.prop(tool_settings, "proportional_edit", icon_only=True)
- sub = row.row(align=True)
- sub.active = tool_settings.proportional_edit != 'DISABLED'
- sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
+ sub = row.row(align=True)
+ sub.active = tool_settings.proportional_edit != 'DISABLED'
+ sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
elif object_mode in {'EDIT', 'PARTICLE_EDIT'}:
row = layout.row(align=True)
@@ -190,7 +212,7 @@ class VIEW3D_HT_header(Header):
sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
# Pivot
- if object_mode in {'OBJECT', 'EDIT', 'POSE'}:
+ if object_mode in {'OBJECT', 'EDIT', 'POSE', 'GPENCIL_EDIT', 'GPENCIL_SCULPT'}:
pivot_point = tool_settings.transform_pivot_point
act_pivot_point = bpy.types.ToolSettings.bl_rna.properties["transform_pivot_point"].enum_items[pivot_point]
row = layout.row(align=True)
@@ -234,13 +256,14 @@ class VIEW3D_MT_editor_menus(Menu):
obj = context.active_object
mode_string = context.mode
edit_object = context.edit_object
- gp_edit = context.gpencil_data and context.gpencil_data.use_stroke_edit_mode
+ gp_edit = obj and obj.mode in {'GPENCIL_EDIT', 'GPENCIL_PAINT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}
layout.menu("VIEW3D_MT_view")
# Select Menu
if gp_edit:
- layout.menu("VIEW3D_MT_select_gpencil")
+ if mode_string not in {'GPENCIL_PAINT', 'GPENCIL_WEIGHT'}:
+ layout.menu("VIEW3D_MT_select_gpencil")
elif mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}:
mesh = obj.data
if mesh.use_paint_mask:
@@ -266,7 +289,15 @@ class VIEW3D_MT_editor_menus(Menu):
layout.menu("INFO_MT_edit_armature_add", text="Add")
if gp_edit:
- layout.menu("VIEW3D_MT_edit_gpencil")
+ if obj and obj.mode == 'GPENCIL_PAINT':
+ layout.menu("VIEW3D_MT_paint_gpencil")
+ elif obj and obj.mode == 'GPENCIL_EDIT':
+ layout.menu("VIEW3D_MT_edit_gpencil")
+ elif obj and obj.mode == 'GPENCIL_SCULPT':
+ layout.menu("VIEW3D_MT_sculpt_gpencil")
+ elif obj and obj.mode == 'GPENCIL_WEIGHT':
+ layout.menu("VIEW3D_MT_weight_gpencil")
+
elif edit_object:
layout.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower())
@@ -1194,6 +1225,7 @@ class VIEW3D_MT_select_gpencil(Menu):
layout.separator()
layout.operator("gpencil.select_linked", text="Linked")
+ layout.operator("gpencil.select_alternate")
layout.operator_menu_enum("gpencil.select_grouped", "type", text="Grouped")
layout.separator()
@@ -1454,6 +1486,7 @@ class INFO_MT_add(Menu):
layout.menu("INFO_MT_armature_add", icon='OUTLINER_OB_ARMATURE')
layout.operator("object.add", text="Lattice", icon='OUTLINER_OB_LATTICE').type = 'LATTICE'
layout.operator_menu_enum("object.empty_add", "type", text="Empty", icon='OUTLINER_OB_EMPTY')
+ layout.operator_menu_enum("object.gpencil_add", "type", text="Grease Pencil", icon='OUTLINER_OB_GREASEPENCIL')
layout.separator()
layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER')
@@ -3110,12 +3143,17 @@ class VIEW3D_MT_edit_gpencil_delete(Menu):
layout.separator()
- layout.operator("gpencil.dissolve")
+ layout.operator_enum("gpencil.dissolve", "type")
layout.separator()
layout.operator("gpencil.active_frames_delete_all")
+ layout.separator()
+
+ layout.operator("gpencil.frame_clean_fill", text="Clean Boundary Strokes").mode = 'ACTIVE'
+ layout.operator("gpencil.frame_clean_fill", text="Clean Boundary Strokes all Frames").mode = 'ALL'
+
# Edit Curve
# draw_curve is used by VIEW3D_MT_edit_curve and VIEW3D_MT_edit_surface
@@ -3476,11 +3514,34 @@ class VIEW3D_MT_edit_armature_delete(Menu):
layout.operator("armature.dissolve", text="Dissolve")
-# ********** GPencil Stroke Edit menu **********
+# ********** Grease Pencil Stroke menus **********
+class VIEW3D_MT_gpencil_simplify(Menu):
+ bl_label = "Simplify"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator("gpencil.stroke_simplify_fixed", text="Fixed")
+ layout.operator("gpencil.stroke_simplify", text="Adaptative")
+
+
+class VIEW3D_MT_paint_gpencil(Menu):
+ bl_label = "Strokes"
+
+ def draw(self, context):
+
+ layout = self.layout
+
+ layout.menu("VIEW3D_MT_gpencil_animation")
+ layout.menu("VIEW3D_MT_edit_gpencil_interpolate")
+
+ layout.separator()
+
+ layout.operator("gpencil.delete", text="Delete Frame").type = 'FRAME'
+ layout.operator("gpencil.active_frames_delete_all")
class VIEW3D_MT_edit_gpencil(Menu):
- bl_label = "GPencil"
+ bl_label = "Strokes"
def draw(self, context):
tool_settings = context.tool_settings
@@ -3488,53 +3549,126 @@ class VIEW3D_MT_edit_gpencil(Menu):
layout = self.layout
layout.menu("VIEW3D_MT_edit_gpencil_transform")
- layout.operator("transform.mirror", text="Mirror")
+
+ layout.separator()
layout.menu("GPENCIL_MT_snap")
layout.separator()
- layout.operator("gpencil.brush_paint", text="Sculpt Strokes").wait_for_input = True
- layout.prop_menu_enum(tool_settings.gpencil_sculpt, "tool", text="Sculpt Brush")
+ layout.menu("VIEW3D_MT_gpencil_animation")
layout.separator()
- layout.menu("VIEW3D_MT_object_animation") # NOTE: provides keyingset access...
layout.menu("VIEW3D_MT_edit_gpencil_interpolate")
layout.separator()
layout.operator("gpencil.duplicate_move", text="Duplicate")
layout.operator("gpencil.stroke_subdivide", text="Subdivide")
+ layout.menu("VIEW3D_MT_gpencil_simplify")
layout.separator()
+ layout.operator_menu_enum("gpencil.stroke_separate", "mode", text="Separate...")
+ layout.operator("gpencil.stroke_split", text="Split")
layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join...")
layout.operator("gpencil.stroke_flip", text="Flip Direction")
layout.separator()
layout.operator("gpencil.copy", text="Copy")
- layout.operator("gpencil.paste", text="Paste")
+ layout.operator("gpencil.paste", text="Paste").type = 'COPY'
+ layout.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE'
+
+ layout.separator()
+
+ layout.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer")
+ layout.operator("gpencil.stroke_change_color", text="Change Color")
+ layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes...")
+
+ layout.separator()
+
+ layout.operator_menu_enum("gpencil.convert", "type", text="Convert to Geometry...")
+
+ layout.separator()
+
+ layout.menu("VIEW3D_MT_edit_gpencil_delete")
+ layout.operator("gpencil.stroke_cyclical_set", text="Toggle Cyclic").type = 'TOGGLE'
+
+ layout.separator()
+
+ layout.operator_menu_enum("gpencil.frame_clean_fill", text="Clean Boundary Strokes...", property="mode")
+
+
+class VIEW3D_MT_sculpt_gpencil(Menu):
+ bl_label = "Strokes"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.menu("VIEW3D_MT_edit_gpencil_transform")
layout.separator()
+ layout.menu("GPENCIL_MT_snap")
- layout.operator("gpencil.reveal")
- layout.operator("gpencil.hide", text="Show Active Layer Only").unselected = True
- layout.operator("gpencil.hide", text="Hide Active Layer").unselected = False
+ layout.separator()
+
+ layout.operator("gpencil.duplicate_move", text="Duplicate")
+ layout.operator("gpencil.stroke_subdivide", text="Subdivide")
+ layout.menu("VIEW3D_MT_gpencil_simplify")
+
+ layout.separator()
+
+ layout.operator_menu_enum("gpencil.stroke_separate", "mode", text="Separate...")
+ layout.operator("gpencil.stroke_split", text="Split")
+ layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join...")
+ layout.operator("gpencil.stroke_flip", text="Flip Direction")
+
+ layout.separator()
+
+ layout.operator("gpencil.copy", text="Copy")
+ layout.operator("gpencil.paste", text="Paste").type = 'COPY'
+ layout.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE'
layout.separator()
layout.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer")
- layout.operator("gpencil.stroke_change_color", text="Move to Color")
+ layout.operator("gpencil.stroke_change_color", text="Change Color")
layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes...")
layout.separator()
layout.operator_menu_enum("gpencil.convert", "type", text="Convert to Geometry...")
- layout.separator()
- layout.menu("VIEW3D_MT_edit_gpencil_delete")
+class VIEW3D_MT_weight_gpencil(Menu):
+ bl_label = "Weights"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("gpencil.vertex_group_invert", text="Invert")
+ layout.operator("gpencil.vertex_group_smooth", text="Smooth")
+
+
+class VIEW3D_MT_gpencil_animation(Menu):
+ bl_label = "Animation"
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.active_object
+ return ob and ob.type == 'GPENCIL' and ob.mode != 'OBJECT'
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("gpencil.blank_frame_add")
+ layout.operator("gpencil.active_frames_delete_all", text="Delete Frame(s)")
+
+ layout.separator()
+ layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame")
+ layout.operator("gpencil.frame_duplicate", text="Duplicate All Layers").mode = 'ALL'
class VIEW3D_MT_edit_gpencil_transform(Menu):
@@ -3595,20 +3729,6 @@ class VIEW3D_MT_view_pie(Menu):
# ********** Panel **********
-class VIEW3D_PT_grease_pencil(GreasePencilDataPanel, Panel):
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
-
- # NOTE: this is just a wrapper around the generic GP Panel
-
-
-class VIEW3D_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
-
- # NOTE: this is just a wrapper around the generic GP Panel
-
-
class VIEW3D_PT_view3d_properties(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
@@ -3720,6 +3840,7 @@ class VIEW3D_PT_object_type_visibility(Panel):
"armature",
"lattice",
"empty",
+ "grease_pencil",
"camera",
"light",
"light_probe",
@@ -4040,6 +4161,8 @@ class VIEW3D_PT_overlay_guides(Panel):
if shading.type == 'MATERIAL':
col.prop(overlay, "show_look_dev")
+ col.prop(overlay, "show_annotation", text="Annotations")
+
class VIEW3D_PT_overlay_object(Panel):
bl_space_type = 'VIEW_3D'
@@ -4578,6 +4701,60 @@ class VIEW3D_PT_transform_orientations(Panel):
row.operator("transform.delete_orientation", text="", icon='X', emboss=False)
+class VIEW3D_PT_overlay_gpencil_options(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
+ bl_label = ""
+
+ @classmethod
+ def poll(cls, context):
+ return context.object and context.object.type == 'GPENCIL'
+
+ def draw_header(self, context):
+ layout = self.layout
+ layout.label(text={
+ 'GPENCIL_PAINT': "Draw Grease Pencil",
+ 'GPENCIL_EDIT': "Edit Grease Pencil",
+ 'GPENCIL_SCULPT': "Sculpt Grease Pencil",
+ 'GPENCIL_WEIGHT': "Weight Grease Pencil",
+ 'OBJECT': "Grease Pencil",
+ }[context.mode])
+
+ def draw(self, context):
+ layout = self.layout
+ view = context.space_data
+ overlay = view.overlay
+
+ layout.prop(overlay, "use_gpencil_onion_skin", text="Onion Skin")
+
+ col = layout.column()
+ row = col.row()
+ row.prop(overlay, "use_gpencil_paper", text="")
+ sub = row.row()
+ sub.active = overlay.use_gpencil_paper
+ sub.prop(overlay, "gpencil_paper_opacity", text="Fade 3D Objects", slider=True)
+
+ col = layout.column()
+ row = col.row()
+ row.prop(overlay, "use_gpencil_grid", text="")
+ sub = row.row()
+ sub.active = overlay.use_gpencil_grid
+ sub.prop(overlay, "gpencil_grid_opacity", text="Canvas Grid", slider=True)
+
+ if overlay.use_gpencil_grid:
+ row = layout.row(align=True)
+ row.prop(overlay, "gpencil_grid_scale")
+ col = row.column()
+ col.prop(overlay, "gpencil_grid_lines", text="Subdivisions")
+ col.prop(overlay, "gpencil_grid_axis")
+
+ if context.object.mode in {'GPENCIL_EDIT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}:
+ layout.prop(overlay, "use_gpencil_edit_lines", text="Edit Lines")
+ layout.prop(overlay, "use_gpencil_multiedit_line_only", text="Show Edit Lines only in multiframe")
+ layout.prop(overlay, "vertex_opacity", text="Vertex Opacity", slider=True)
+
+
class VIEW3D_PT_quad_view(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
@@ -4605,6 +4782,14 @@ class VIEW3D_PT_quad_view(Panel):
row.prop(region, "use_box_clip")
+# Annotation properties
+class VIEW3D_PT_grease_pencil(GreasePencilDataPanel, Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'UI'
+
+ # NOTE: this is just a wrapper around the generic GP Panel
+
+
class VIEW3D_PT_view3d_stereo(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
@@ -4684,6 +4869,27 @@ class VIEW3D_PT_context_properties(Panel):
rna_prop_ui.draw(self.layout, context, member, object, False)
+# Grease Pencil Object - Multiframe falloff tools
+class VIEW3D_PT_gpencil_multi_frame(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Multi Frame"
+
+ @staticmethod
+ def draw(self, context):
+ gpd = context.gpencil_data
+ settings = context.tool_settings.gpencil_sculpt
+
+ layout = self.layout
+ col = layout.column(align=True)
+ col.prop(settings, "use_multiframe_falloff")
+
+ # Falloff curve
+ if gpd.use_multiedit and settings.use_multiframe_falloff:
+ layout.template_curve_mapping(settings, "multiframe_falloff_curve", brush=True)
+
+
+
classes = (
VIEW3D_HT_header,
VIEW3D_MT_editor_menus,
@@ -4791,8 +4997,13 @@ classes = (
VIEW3D_MT_edit_mesh_clean,
VIEW3D_MT_edit_mesh_delete,
VIEW3D_MT_edit_mesh_showhide,
+ VIEW3D_MT_paint_gpencil,
VIEW3D_MT_edit_gpencil,
VIEW3D_MT_edit_gpencil_delete,
+ VIEW3D_MT_sculpt_gpencil,
+ VIEW3D_MT_weight_gpencil,
+ VIEW3D_MT_gpencil_animation,
+ VIEW3D_MT_gpencil_simplify,
VIEW3D_MT_edit_curve,
VIEW3D_MT_edit_curve_ctrlpoints,
VIEW3D_MT_edit_curve_segments,
@@ -4815,12 +5026,12 @@ classes = (
VIEW3D_MT_edit_gpencil_interpolate,
VIEW3D_MT_object_mode_pie,
VIEW3D_MT_view_pie,
- VIEW3D_PT_grease_pencil,
- VIEW3D_PT_grease_pencil_palettecolor,
VIEW3D_PT_view3d_properties,
VIEW3D_PT_view3d_camera_lock,
VIEW3D_PT_view3d_cursor,
VIEW3D_PT_object_type_visibility,
+ VIEW3D_PT_grease_pencil,
+ VIEW3D_PT_gpencil_multi_frame,
VIEW3D_PT_quad_view,
VIEW3D_PT_view3d_stereo,
VIEW3D_PT_shading,
@@ -4849,6 +5060,7 @@ classes = (
VIEW3D_PT_pivot_point,
VIEW3D_PT_snapping,
VIEW3D_PT_transform_orientations,
+ VIEW3D_PT_overlay_gpencil_options,
VIEW3D_PT_context_properties,
)
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 87c6a3840ae..70d8c4089d3 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -20,19 +20,17 @@
import bpy
from bpy.types import Menu, Panel, UIList
from .properties_grease_pencil_common import (
- GreasePencilDrawingToolsPanel,
- GreasePencilStrokeEditPanel,
- GreasePencilInterpolatePanel,
- GreasePencilStrokeSculptPanel,
- GreasePencilBrushPanel,
- GreasePencilBrushCurvesPanel
-)
+ GreasePencilStrokeEditPanel,
+ GreasePencilStrokeSculptPanel,
+ GreasePencilAppearancePanel,
+ )
from .properties_paint_common import (
- UnifiedPaintPanel,
- brush_texture_settings,
- brush_texpaint_common,
- brush_mask_texture_settings,
-)
+ UnifiedPaintPanel,
+ brush_texture_settings,
+ brush_texpaint_common,
+ brush_mask_texture_settings,
+ )
+from bl_operators.presets import PresetMenu
class View3DPanel:
@@ -70,6 +68,12 @@ def draw_vpaint_symmetry(layout, vpaint):
col.use_property_split = True
col.prop(vpaint, "radial_symmetry", text="Radial")
+# Most of these panels should not be visible in GP edit modes
+def is_not_gpencil_edit_mode(context):
+ is_gpmode = context.active_object and \
+ context.active_object.mode in {'GPENCIL_EDIT', 'GPENCIL_PAINT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}
+ return not is_gpmode
+
# ********** default tools for editmode_mesh ****************
@@ -1341,9 +1345,272 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, Panel):
sub.prop(pe, "fade_frames", slider=True)
-# Grease Pencil drawing tools
-class VIEW3D_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
+# ********** grease pencil object tool panels ****************
+
+# Grease Pencil drawing brushes
+class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel):
+ bl_context = ".greasepencil_paint"
+ bl_label = "Brush"
+
+ @classmethod
+ def poll(cls, context):
+ is_3d_view = context.space_data.type == 'VIEW_3D'
+ if is_3d_view:
+ if context.gpencil_data is None:
+ return False
+
+ gpd = context.gpencil_data
+ return bool(gpd.is_stroke_paint_mode)
+ else:
+ return True
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ ts = context.scene.tool_settings
+ settings = ts.gpencil_paint
+
+ row = layout.row()
+ col = row.column()
+ col.template_ID_preview(settings, "brush", new="brush.add_gpencil", rows=3, cols=8)
+
+ col = row.column()
+ brush = context.active_gpencil_brush
+ gp_settings = brush.gpencil_settings
+
+ sub = col.column(align=True)
+ sub.operator("gpencil.brush_presets_create", icon='HELP', text="")
+
+ if brush is not None:
+ # XXX: Items in "sub" currently show up beside the brush selector in a separate column
+ if gp_settings.gpencil_brush_type == 'ERASE':
+ sub.prop(gp_settings, "default_eraser", text="")
+
+ # Brush details
+ if gp_settings.gpencil_brush_type == 'ERASE':
+ col = layout.column(align=True)
+ col.prop(brush, "size", text="Radius")
+
+ col.separator()
+ row = col.row()
+ row.prop(gp_settings, "eraser_mode", expand=True)
+ elif gp_settings.gpencil_brush_type == 'FILL':
+ col = layout.column(align=True)
+ col.prop(gp_settings, "gpencil_fill_leak", text="Leak Size")
+ col.prop(brush, "size", text="Thickness")
+ col.prop(gp_settings, "gpencil_fill_simplyfy_level", text="Simplify")
+
+ col = layout.row(align=True)
+ col.template_ID(gp_settings, "material")
+
+ row = layout.row(align=True)
+ row.prop(gp_settings, "gpencil_fill_draw_mode", text="Boundary Draw Mode")
+ row.prop(gp_settings, "gpencil_fill_show_boundary", text="", icon='GRID')
+
+ col = layout.column(align=True)
+ col.enabled = gp_settings.gpencil_fill_draw_mode != "STROKE"
+ col.prop(gp_settings, "gpencil_fill_hide", text="Hide Transparent Lines")
+ sub = col.row(align=True)
+ sub.enabled = gp_settings.gpencil_fill_hide
+ sub.prop(gp_settings, "gpencil_fill_threshold", text="Threshold")
+ else: # bgpsettings.gpencil_brush_type == 'DRAW':
+ row = layout.row(align=True)
+ row.prop(brush, "size", text="Radius")
+ row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE')
+ row = layout.row(align=True)
+ row.prop(gp_settings, "pen_strength", slider=True)
+ row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE')
+
+ row = layout.row(align=True)
+ row.template_ID(gp_settings, "material")
+
+
+# Grease Pencil drawing brushes options
+class VIEW3D_PT_tools_grease_pencil_brush_option(View3DPanel, Panel):
+ bl_context = ".greasepencil_paint"
+ bl_label = "Options"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw_header_preset(self, context):
+ VIEW3D_PT_gpencil_brush_presets.draw_panel_header(self.layout)
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ brush = context.active_gpencil_brush
+ gp_settings = brush.gpencil_settings
+
+ if brush is not None:
+ col = layout.column(align=True)
+ col.prop(gp_settings, "input_samples")
+ col.separator()
+
+ col.prop(gp_settings, "active_smooth_factor")
+ col.separator()
+
+ col.prop(gp_settings, "angle", slider=True)
+ col.prop(gp_settings, "angle_factor", text="Factor", slider=True)
+ col.separator()
+
+
+class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(View3DPanel, Panel):
+ bl_context = ".greasepencil_paint"
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
+ bl_label = "Stabilizer"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ brush = context.active_gpencil_brush
+ gp_settings = brush.gpencil_settings
+
+ return brush is not None and gp_settings.gpencil_brush_type == 'DRAW'
+
+ def draw_header(self, context):
+ brush = context.active_gpencil_brush
+ gp_settings = brush.gpencil_settings
+ self.layout.prop(gp_settings, "use_stabilizer", text="")
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ brush = context.active_gpencil_brush
+ gp_settings = brush.gpencil_settings
+ layout.active = gp_settings.use_stabilizer
+
+ layout.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
+ layout.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
+
+
+class VIEW3D_PT_tools_grease_pencil_brush_settings(View3DPanel, Panel):
+ bl_context = ".greasepencil_paint"
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
+ bl_label = "Post-processing Settings"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ brush = context.active_gpencil_brush
+
+ return brush is not None
+
+ def draw_header(self, context):
+ brush = context.active_gpencil_brush
+ gp_settings = brush.gpencil_settings
+ self.layout.prop(gp_settings, "enable_settings", text="")
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ brush = context.active_gpencil_brush
+ gp_settings = brush.gpencil_settings
+ layout.active = gp_settings.enable_settings
+
+ layout.prop(gp_settings, "pen_smooth_factor")
+ layout.prop(gp_settings, "pen_smooth_steps")
+
+ layout.prop(gp_settings, "pen_thick_smooth_factor")
+ layout.prop(gp_settings, "pen_thick_smooth_steps")
+
+ layout.prop(gp_settings, "pen_subdivision_steps")
+ layout.prop(gp_settings, "random_subdiv", text="Randomness", slider=True)
+
+
+class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
+ bl_context = ".greasepencil_paint"
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
+ bl_label = "Random Settings"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ brush = context.active_gpencil_brush
+
+ return brush is not None
+
+ def draw_header(self, context):
+ brush = context.active_gpencil_brush
+ gp_settings = brush.gpencil_settings
+ self.layout.prop(gp_settings, "enable_random", text="")
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ brush = context.active_gpencil_brush
+ gp_settings = brush.gpencil_settings
+ layout.active = gp_settings.enable_random
+
+ layout.prop(gp_settings, "random_pressure", text="Pressure", slider=True)
+ layout.prop(gp_settings, "random_strength", text="Strength", slider=True)
+ layout.prop(gp_settings, "uv_random", text="UV", slider=True)
+
+ row = layout.row(align=True)
+ row.prop(gp_settings, "pen_jitter", slider=True)
+ row.prop(gp_settings, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE')
+
+
+# Grease Pencil drawingcurves
+class VIEW3D_PT_tools_grease_pencil_brushcurves(View3DPanel, Panel):
+ bl_context = ".greasepencil_paint"
+ bl_label = "Curves"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ brush = context.active_gpencil_brush
+ gp_settings = brush.gpencil_settings
+
+ # Brush
+ layout.label("Sensitivity")
+ layout.template_curve_mapping(gp_settings, "curve_sensitivity", brush=True)
+
+ layout.label("Strength")
+ layout.template_curve_mapping(gp_settings, "curve_strength", brush=True)
+
+ layout.label("Jitter")
+ layout.template_curve_mapping(gp_settings, "curve_jitter", brush=True)
+
+
+# Grease Pencil create shapes
+class VIEW3D_PT_tools_grease_pencil_shapes(View3DPanel, Panel):
bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Shapes"
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.active_object
+ return ob and ob.type == 'GPENCIL'
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ col = layout.column(align=True)
+ col.operator("gpencil.primitive", text="Line", icon='IPO_CONSTANT').type = 'LINE'
+ col.operator("gpencil.primitive", text="Rectangle", icon='UV_FACESEL').type = 'BOX'
+ col.operator("gpencil.primitive", text="Circle", icon='ANTIALIASED').type = 'CIRCLE'
+
+ layout.operator("object.gpencil_add", text="Monkey", icon='MONKEY').type = 'MONKEY'
# Grease Pencil stroke editing tools
@@ -1352,24 +1619,109 @@ class VIEW3D_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
# Grease Pencil stroke interpolation tools
-class VIEW3D_PT_tools_grease_pencil_interpolate(GreasePencilInterpolatePanel, Panel):
+class VIEW3D_PT_tools_grease_pencil_interpolate(Panel):
bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Interpolate"
+
+ @classmethod
+ def poll(cls, context):
+ if context.gpencil_data is None:
+ return False
+
+ gpd = context.gpencil_data
+ return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ settings = context.tool_settings.gpencil_interpolate
+
+ col = layout.column(align=True)
+ col.label("Interpolate Strokes")
+ col.operator("gpencil.interpolate", text="Interpolate")
+ col.operator("gpencil.interpolate_sequence", text="Sequence")
+ col.operator("gpencil.interpolate_reverse", text="Remove Breakdowns")
+
+ col = layout.column(align=True)
+ col.label(text="Options:")
+ col.prop(settings, "interpolate_all_layers")
+ col.prop(settings, "interpolate_selected_only")
+
+ col = layout.column(align=True)
+ col.label(text="Sequence Options:")
+ col.prop(settings, "type")
+ if settings.type == 'CUSTOM':
+ # TODO: Options for loading/saving curve presets?
+ col.template_curve_mapping(settings, "interpolation_curve", brush=True)
+ elif settings.type != 'LINEAR':
+ col.prop(settings, "easing")
+
+ if settings.type == 'BACK':
+ layout.prop(settings, "back")
+ elif setting.type == 'ELASTIC':
+ sub = layout.column(align=True)
+ sub.prop(settings, "amplitude")
+ sub.prop(settings, "period")
# Grease Pencil stroke sculpting tools
-class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
- bl_space_type = 'VIEW_3D'
+class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, View3DPanel, Panel):
+ bl_context = ".greasepencil_sculpt"
+ bl_category = "Tools"
+ bl_label = "Sculpt Strokes"
-# Grease Pencil drawing brushes
-class VIEW3D_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
- bl_space_type = 'VIEW_3D'
+# Grease Pencil weight painting tools
+class VIEW3D_PT_tools_grease_pencil_weight_paint(View3DPanel, Panel):
+ bl_context = ".greasepencil_weight"
+ bl_category = "Tools"
+ bl_label = "Weight Paint"
-# Grease Pencil drawingcurves
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+ gpd = context.gpencil_data
+ settings = context.tool_settings.gpencil_sculpt
+ tool = settings.tool
+ brush = settings.brush
-class VIEW3D_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
- bl_space_type = 'VIEW_3D'
+ layout.template_icon_view(settings, "weight_tool", show_labels=True)
+
+ col = layout.column()
+ col.prop(brush, "size", slider=True)
+ row = col.row(align=True)
+ row.prop(brush, "strength", slider=True)
+ row.prop(brush, "use_pressure_strength", text="")
+
+ col.prop(brush, "use_falloff")
+
+
+# Grease Pencil Brush Appeareance (one for each mode)
+class VIEW3D_PT_tools_grease_pencil_paint_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
+ bl_context = ".greasepencil_paint"
+ bl_label = "Appearance"
+
+
+class VIEW3D_PT_tools_grease_pencil_sculpt_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
+ bl_context = ".greasepencil_sculpt"
+ bl_label = "Appearance"
+
+
+class VIEW3D_PT_tools_grease_pencil_weight_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
+ bl_context = ".greasepencil_weight"
+ bl_label = "Appearance"
+
+
+class VIEW3D_PT_gpencil_brush_presets(PresetMenu):
+ """Brush settings"""
+ bl_label = "Brush Presets"
+ preset_subdir = "gpencil_brush"
+ preset_operator = "script.execute_preset"
+ preset_add_operator = "scene.gpencil_brush_preset_add"
classes = (
@@ -1401,12 +1753,21 @@ classes = (
VIEW3D_PT_tools_projectpaint,
VIEW3D_MT_tools_projectpaint_stencil,
VIEW3D_PT_tools_particlemode,
- VIEW3D_PT_tools_grease_pencil_draw,
- VIEW3D_PT_tools_grease_pencil_edit,
- VIEW3D_PT_tools_grease_pencil_interpolate,
- VIEW3D_PT_tools_grease_pencil_sculpt,
+
+ VIEW3D_PT_gpencil_brush_presets,
VIEW3D_PT_tools_grease_pencil_brush,
+ VIEW3D_PT_tools_grease_pencil_brush_option,
+ VIEW3D_PT_tools_grease_pencil_brush_settings,
+ VIEW3D_PT_tools_grease_pencil_brush_stabilizer,
+ VIEW3D_PT_tools_grease_pencil_brush_random,
VIEW3D_PT_tools_grease_pencil_brushcurves,
+ VIEW3D_PT_tools_grease_pencil_shapes,
+ VIEW3D_PT_tools_grease_pencil_sculpt,
+ VIEW3D_PT_tools_grease_pencil_weight_paint,
+ VIEW3D_PT_tools_grease_pencil_paint_appearance,
+ VIEW3D_PT_tools_grease_pencil_sculpt_appearance,
+ VIEW3D_PT_tools_grease_pencil_weight_appearance,
+ VIEW3D_PT_tools_grease_pencil_interpolate,
)
if __name__ == "__main__": # only for live edit.
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();