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:
authorLukas Tönne <lukas.toenne@gmail.com>2016-08-09 17:37:15 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2016-08-09 17:37:15 +0300
commit4a801f6c6f0421ffd515c12422dd197441440520 (patch)
tree5415e844b460bb2aa07b9467c72e13abc2e61228 /source/blender
parent49c63d46db8c055152d9e431e89405f9b51a4bbe (diff)
parent02719521d2e25abcc8ffcccc086d3a651986f52f (diff)
Merge branch 'master' into object_nodesobject_nodes
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/CMakeLists.txt4
-rw-r--r--source/blender/alembic/ABC_alembic.h110
-rw-r--r--source/blender/alembic/CMakeLists.txt81
-rw-r--r--source/blender/alembic/intern/abc_camera.cc162
-rw-r--r--source/blender/alembic/intern/abc_camera.h61
-rw-r--r--source/blender/alembic/intern/abc_curves.cc355
-rw-r--r--source/blender/alembic/intern/abc_curves.h65
-rw-r--r--source/blender/alembic/intern/abc_customdata.cc379
-rw-r--r--source/blender/alembic/intern/abc_customdata.h93
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc600
-rw-r--r--source/blender/alembic/intern/abc_exporter.h112
-rw-r--r--source/blender/alembic/intern/abc_hair.cc290
-rw-r--r--source/blender/alembic/intern/abc_hair.h66
-rw-r--r--source/blender/alembic/intern/abc_mesh.cc1213
-rw-r--r--source/blender/alembic/intern/abc_mesh.h152
-rw-r--r--source/blender/alembic/intern/abc_nurbs.cc367
-rw-r--r--source/blender/alembic/intern/abc_nurbs.h63
-rw-r--r--source/blender/alembic/intern/abc_object.cc238
-rw-r--r--source/blender/alembic/intern/abc_object.h169
-rw-r--r--source/blender/alembic/intern/abc_points.cc198
-rw-r--r--source/blender/alembic/intern/abc_points.h70
-rw-r--r--source/blender/alembic/intern/abc_transform.cc152
-rw-r--r--source/blender/alembic/intern/abc_transform.h73
-rw-r--r--source/blender/alembic/intern/abc_util.cc437
-rw-r--r--source/blender/alembic/intern/abc_util.h125
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc1136
-rw-r--r--source/blender/blenkernel/BKE_animsys.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_cachefile.h67
-rw-r--r--source/blender/blenkernel/BKE_cloth.h1
-rw-r--r--source/blender/blenkernel/BKE_colortools.h2
-rw-r--r--source/blender/blenkernel/BKE_context.h9
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h6
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h69
-rw-r--r--source/blender/blenkernel/BKE_idcode.h2
-rw-r--r--source/blender/blenkernel/BKE_library.h3
-rw-r--r--source/blender/blenkernel/BKE_main.h5
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h3
-rw-r--r--source/blender/blenkernel/BKE_paint.h4
-rw-r--r--source/blender/blenkernel/BKE_particle.h7
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h2
-rw-r--r--source/blender/blenkernel/BKE_tracking.h1
-rw-r--r--source/blender/blenkernel/CMakeLists.txt9
-rw-r--r--source/blender/blenkernel/intern/action.c5
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c343
-rw-r--r--source/blender/blenkernel/intern/armature.c5
-rw-r--r--source/blender/blenkernel/intern/bpath.c7
-rw-r--r--source/blender/blenkernel/intern/brush.c5
-rw-r--r--source/blender/blenkernel/intern/cachefile.c173
-rw-r--r--source/blender/blenkernel/intern/camera.c5
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c2
-rw-r--r--source/blender/blenkernel/intern/cloth.c25
-rw-r--r--source/blender/blenkernel/intern/colortools.c85
-rw-r--r--source/blender/blenkernel/intern/constraint.c74
-rw-r--r--source/blender/blenkernel/intern/context.c20
-rw-r--r--source/blender/blenkernel/intern/curve.c5
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c52
-rw-r--r--source/blender/blenkernel/intern/fcurve.c98
-rw-r--r--source/blender/blenkernel/intern/gpencil.c834
-rw-r--r--source/blender/blenkernel/intern/group.c5
-rw-r--r--source/blender/blenkernel/intern/idcode.c53
-rw-r--r--source/blender/blenkernel/intern/idprop.c11
-rw-r--r--source/blender/blenkernel/intern/image.c6
-rw-r--r--source/blender/blenkernel/intern/key.c5
-rw-r--r--source/blender/blenkernel/intern/lamp.c5
-rw-r--r--source/blender/blenkernel/intern/lattice.c5
-rw-r--r--source/blender/blenkernel/intern/library.c230
-rw-r--r--source/blender/blenkernel/intern/library_query.c71
-rw-r--r--source/blender/blenkernel/intern/library_remap.c7
-rw-r--r--source/blender/blenkernel/intern/linestyle.c5
-rw-r--r--source/blender/blenkernel/intern/mask.c5
-rw-r--r--source/blender/blenkernel/intern/material.c8
-rw-r--r--source/blender/blenkernel/intern/mball.c5
-rw-r--r--source/blender/blenkernel/intern/mesh.c5
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c1
-rw-r--r--source/blender/blenkernel/intern/movieclip.c26
-rw-r--r--source/blender/blenkernel/intern/node.c5
-rw-r--r--source/blender/blenkernel/intern/object.c5
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c1
-rw-r--r--source/blender/blenkernel/intern/paint.c38
-rw-r--r--source/blender/blenkernel/intern/particle.c12
-rw-r--r--source/blender/blenkernel/intern/particle_system.c43
-rw-r--r--source/blender/blenkernel/intern/pointcache.c4
-rw-r--r--source/blender/blenkernel/intern/scene.c23
-rw-r--r--source/blender/blenkernel/intern/sequencer.c49
-rw-r--r--source/blender/blenkernel/intern/smoke.c25
-rw-r--r--source/blender/blenkernel/intern/softbody.c150
-rw-r--r--source/blender/blenkernel/intern/speaker.c5
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c18
-rw-r--r--source/blender/blenkernel/intern/text.c5
-rw-r--r--source/blender/blenkernel/intern/texture.c5
-rw-r--r--source/blender/blenkernel/intern/tracking.c129
-rw-r--r--source/blender/blenkernel/intern/world.c5
-rw-r--r--source/blender/blenlib/intern/BLI_heap.c3
-rw-r--r--source/blender/blenlib/intern/scanfill_utils.c2
-rw-r--r--source/blender/blenloader/CMakeLists.txt7
-rw-r--r--source/blender/blenloader/intern/readfile.c149
-rw-r--r--source/blender/blenloader/intern/versioning_270.c109
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c5
-rw-r--r--source/blender/blenloader/intern/writefile.c37
-rw-r--r--source/blender/blentranslation/BLT_translation.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c2
-rw-r--r--source/blender/compositor/nodes/COM_FilterNode.cpp2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h4
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h10
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc1
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc33
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc24
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc10
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc3
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc17
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h5
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc22
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.h2
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.cc2
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.h2
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.cc9
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.h6
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c91
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c7
-rw-r--r--source/blender/editors/animation/anim_filter.c72
-rw-r--r--source/blender/editors/animation/keyframes_draw.c32
-rw-r--r--source/blender/editors/animation/keyframing.c13
-rw-r--r--source/blender/editors/curve/editcurve_paint.c4
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c563
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c12
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c403
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c55
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c1830
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c345
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h127
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c80
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c482
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c129
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c379
-rw-r--r--source/blender/editors/include/ED_anim_api.h2
-rw-r--r--source/blender/editors/include/ED_gpencil.h12
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h3
-rw-r--r--source/blender/editors/include/UI_icons.h4
-rw-r--r--source/blender/editors/include/UI_interface.h7
-rw-r--r--source/blender/editors/interface/interface_handlers.c4
-rw-r--r--source/blender/editors/interface/interface_icons.c2
-rw-r--r--source/blender/editors/interface/interface_intern.h2
-rw-r--r--source/blender/editors/interface/interface_regions.c32
-rw-r--r--source/blender/editors/interface/interface_templates.c87
-rw-r--r--source/blender/editors/io/CMakeLists.txt14
-rw-r--r--source/blender/editors/io/io_alembic.c458
-rw-r--r--source/blender/editors/io/io_alembic.h37
-rw-r--r--source/blender/editors/io/io_cache.c162
-rw-r--r--source/blender/editors/io/io_cache.h37
-rw-r--r--source/blender/editors/io/io_ops.c16
-rw-r--r--source/blender/editors/object/object_add.c17
-rw-r--r--source/blender/editors/object/object_constraint.c7
-rw-r--r--source/blender/editors/object/object_relations.c14
-rw-r--r--source/blender/editors/render/render_opengl.c97
-rw-r--r--source/blender/editors/render/render_preview.c2
-rw-r--r--source/blender/editors/screen/screen_context.c64
-rw-r--r--source/blender/editors/screen/screen_edit.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c5
-rw-r--r--source/blender/editors/space_action/action_buttons.c2
-rw-r--r--source/blender/editors/space_action/action_edit.c2
-rw-r--r--source/blender/editors/space_clip/clip_toolbar.c2
-rw-r--r--source/blender/editors/space_clip/space_clip.c2
-rw-r--r--source/blender/editors/space_file/filelist.c7
-rw-r--r--source/blender/editors/space_file/filesel.c4
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c7
-rw-r--r--source/blender/editors/space_image/image_buttons.c2
-rw-r--r--source/blender/editors/space_logic/logic_buttons.c2
-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.c2
-rw-r--r--source/blender/editors/space_node/node_buttons.c2
-rw-r--r--source/blender/editors/space_node/node_group.c45
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c7
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h2
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c11
-rw-r--r--source/blender/editors/space_sequencer/sequencer_buttons.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c11
-rw-r--r--source/blender/editors/space_text/text_header.c2
-rw-r--r--source/blender/editors/space_time/space_time.c69
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c12
-rw-r--r--source/blender/editors/space_view3d/drawobject.c2
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c6
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c12
-rw-r--r--source/blender/editors/transform/transform.c158
-rw-r--r--source/blender/editors/transform/transform.h1
-rw-r--r--source/blender/editors/transform/transform_conversions.c84
-rw-r--r--source/blender/editors/transform/transform_generics.c4
-rw-r--r--source/blender/editors/transform/transform_manipulator.c55
-rw-r--r--source/blender/editors/transform/transform_snap.c9
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp1
-rw-r--r--source/blender/freestyle/intern/python/BPy_ViewShape.cpp14
-rw-r--r--source/blender/freestyle/intern/scene_graph/Rep.h18
-rw-r--r--source/blender/freestyle/intern/view_map/BoxGrid.cpp10
-rw-r--r--source/blender/freestyle/intern/view_map/Silhouette.h15
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMap.h8
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp1
-rw-r--r--source/blender/freestyle/intern/winged_edge/WEdge.cpp1
-rw-r--r--source/blender/freestyle/intern/winged_edge/WEdge.h13
-rw-r--r--source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp1
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c6
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h1
-rw-r--r--source/blender/gpu/intern/gpu_material.c3
-rw-r--r--source/blender/gpu/intern/gpu_texture.c16
-rw-r--r--source/blender/makesdna/DNA_ID.h122
-rw-r--r--source/blender/makesdna/DNA_action_types.h4
-rw-r--r--source/blender/makesdna/DNA_anim_types.h4
-rw-r--r--source/blender/makesdna/DNA_cachefile_types.h84
-rw-r--r--source/blender/makesdna/DNA_cloth_types.h2
-rw-r--r--source/blender/makesdna/DNA_color_types.h3
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h7
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h144
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h22
-rw-r--r--source/blender/makesdna/DNA_object_force.h2
-rw-r--r--source/blender/makesdna/DNA_particle_types.h1
-rw-r--r--source/blender/makesdna/DNA_scene_types.h23
-rw-r--r--source/blender/makesdna/DNA_screen_types.h17
-rw-r--r--source/blender/makesdna/DNA_space_types.h1
-rw-r--r--source/blender/makesdna/intern/makesdna.c2
-rw-r--r--source/blender/makesrna/RNA_access.h10
-rw-r--r--source/blender/makesrna/RNA_enum_types.h2
-rw-r--r--source/blender/makesrna/RNA_types.h10
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt8
-rw-r--r--source/blender/makesrna/intern/makesrna.c1
-rw-r--r--source/blender/makesrna/intern/rna_ID.c9
-rw-r--r--source/blender/makesrna/intern/rna_access.c19
-rw-r--r--source/blender/makesrna/intern/rna_cachefile.c169
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c22
-rw-r--r--source/blender/makesrna/intern/rna_color.c3
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c26
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c8
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c825
-rw-r--r--source/blender/makesrna/intern/rna_internal.h2
-rw-r--r--source/blender/makesrna/intern/rna_main.c7
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c18
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c46
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c14
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c5
-rw-r--r--source/blender/makesrna/intern/rna_particle.c4
-rw-r--r--source/blender/makesrna/intern/rna_scene.c317
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c111
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c31
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c16
-rw-r--r--source/blender/makesrna/intern/rna_space.c4
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c5
-rw-r--r--source/blender/modifiers/CMakeLists.txt8
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c2
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c197
-rw-r--r--source/blender/modifiers/intern/MOD_util.c1
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp8
-rw-r--r--source/blender/python/BPY_extern.h3
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.c8
-rw-r--r--source/blender/python/generic/idprop_py_api.c142
-rw-r--r--source/blender/python/generic/py_capi_utils.c29
-rw-r--r--source/blender/python/generic/py_capi_utils.h1
-rw-r--r--source/blender/python/intern/CMakeLists.txt13
-rw-r--r--source/blender/python/intern/bpy_app.c3
-rw-r--r--source/blender/python/intern/bpy_app_alembic.c113
-rw-r--r--source/blender/python/intern/bpy_app_alembic.h38
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c7
-rw-r--r--source/blender/python/intern/bpy_app_translations.c2
-rw-r--r--source/blender/python/intern/bpy_driver.c73
-rw-r--r--source/blender/python/intern/bpy_driver.h3
-rw-r--r--source/blender/python/intern/bpy_intern_string.c6
-rw-r--r--source/blender/python/intern/bpy_intern_string.h2
-rw-r--r--source/blender/python/intern/bpy_library_load.c4
-rw-r--r--source/blender/python/intern/bpy_rna_driver.c21
-rw-r--r--source/blender/python/intern/bpy_rna_driver.h4
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c790
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h3
-rw-r--r--source/blender/render/intern/include/render_result.h3
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.cpp4
-rw-r--r--source/blender/render/intern/source/pipeline.c29
-rw-r--r--source/blender/render/intern/source/render_result.c5
-rw-r--r--source/blender/windowmanager/WM_api.h3
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c5
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c18
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c2
-rw-r--r--source/blender/windowmanager/intern/wm_window.c15
292 files changed, 18172 insertions, 2059 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 12f27b5ecec..c094abbd489 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -31,6 +31,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_armature_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_boid_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_brush_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cachefile_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_camera_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cloth_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_color_types.h
@@ -154,3 +155,6 @@ if(WITH_FREESTYLE)
add_subdirectory(freestyle)
endif()
+if(WITH_ALEMBIC)
+ add_subdirectory(alembic)
+endif()
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h
new file mode 100644
index 00000000000..cf121f8488c
--- /dev/null
+++ b/source/blender/alembic/ABC_alembic.h
@@ -0,0 +1,110 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_ALEMBIC_H__
+#define __ABC_ALEMBIC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bContext;
+struct DerivedMesh;
+struct ListBase;
+struct Object;
+struct Scene;
+
+typedef struct AbcArchiveHandle AbcArchiveHandle;
+
+enum {
+ ABC_ARCHIVE_OGAWA = 0,
+ ABC_ARCHIVE_HDF5 = 1,
+};
+
+int ABC_get_version(void);
+
+struct AlembicExportParams {
+ double frame_start;
+ double frame_end;
+
+ double frame_step_xform;
+ double frame_step_shape;
+
+ double shutter_open;
+ double shutter_close;
+
+ /* bools */
+ unsigned int selected_only : 1;
+ unsigned int uvs : 1;
+ unsigned int normals : 1;
+ unsigned int vcolors : 1;
+ unsigned int apply_subdiv : 1;
+ unsigned int flatten_hierarchy : 1;
+ unsigned int visible_layers_only : 1;
+ unsigned int renderable_only : 1;
+ unsigned int face_sets : 1;
+ unsigned int use_subdiv_schema : 1;
+ unsigned int packuv : 1;
+
+ unsigned int compression_type : 1;
+ float global_scale;
+};
+
+void ABC_export(
+ struct Scene *scene,
+ struct bContext *C,
+ const char *filepath,
+ const struct AlembicExportParams *params);
+
+void ABC_import(struct bContext *C,
+ const char *filepath,
+ float scale,
+ bool is_sequence,
+ bool set_frame_range,
+ int sequence_len,
+ int offset,
+ bool validate_meshes);
+
+AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *object_paths);
+
+void ABC_free_handle(AbcArchiveHandle *handle);
+
+void ABC_get_transform(AbcArchiveHandle *handle,
+ struct Object *ob,
+ const char *object_path,
+ float r_mat[4][4],
+ float time,
+ float scale);
+
+struct DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle,
+ struct Object *ob,
+ struct DerivedMesh *dm,
+ const char *object_path,
+ const float time,
+ const char **err_str,
+ int flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ABC_ALEMBIC_H__ */
diff --git a/source/blender/alembic/CMakeLists.txt b/source/blender/alembic/CMakeLists.txt
new file mode 100644
index 00000000000..42bd6a9c340
--- /dev/null
+++ b/source/blender/alembic/CMakeLists.txt
@@ -0,0 +1,81 @@
+# ***** 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) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Kevin Dietrich.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../blenkernel
+ ../blenlib
+ ../blenloader
+ ../editors/include
+ ../makesdna
+ ../makesrna
+ ../windowmanager
+ ../../../intern/guardedalloc
+)
+
+set(INC_SYS
+ ${ALEMBIC_INCLUDE_DIRS}
+ ${HDF5_INCLUDE_DIRS}
+ ${OPENEXR_INCLUDE_DIRS}
+)
+if(APPLE OR WIN32)
+ list(APPEND INC_SYS
+ ${BOOST_INCLUDE_DIR}
+ )
+endif()
+
+set(SRC
+ intern/abc_camera.cc
+ intern/abc_customdata.cc
+ intern/abc_curves.cc
+ intern/abc_exporter.cc
+ intern/abc_hair.cc
+ intern/abc_mesh.cc
+ intern/abc_nurbs.cc
+ intern/abc_object.cc
+ intern/abc_points.cc
+ intern/abc_transform.cc
+ intern/abc_util.cc
+ intern/alembic_capi.cc
+
+ ABC_alembic.h
+ intern/abc_camera.h
+ intern/abc_customdata.h
+ intern/abc_curves.h
+ intern/abc_exporter.h
+ intern/abc_hair.h
+ intern/abc_mesh.h
+ intern/abc_nurbs.h
+ intern/abc_object.h
+ intern/abc_points.h
+ intern/abc_transform.h
+ intern/abc_util.h
+)
+
+if(WITH_ALEMBIC_HDF5)
+ add_definitions(-DWITH_ALEMBIC_HDF5)
+endif()
+
+blender_add_lib(bf_alembic "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/alembic/intern/abc_camera.cc b/source/blender/alembic/intern/abc_camera.cc
new file mode 100644
index 00000000000..38a6d3d33cf
--- /dev/null
+++ b/source/blender/alembic/intern/abc_camera.cc
@@ -0,0 +1,162 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_camera.h"
+
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "DNA_camera_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_camera.h"
+#include "BKE_object.h"
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+}
+
+using Alembic::AbcGeom::ICamera;
+using Alembic::AbcGeom::ICompoundProperty;
+using Alembic::AbcGeom::IFloatProperty;
+using Alembic::AbcGeom::ISampleSelector;
+
+using Alembic::AbcGeom::OCamera;
+using Alembic::AbcGeom::OFloatProperty;
+
+using Alembic::AbcGeom::CameraSample;
+using Alembic::AbcGeom::kWrapExisting;
+
+/* ************************************************************************** */
+
+AbcCameraWriter::AbcCameraWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings)
+ : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+{
+ OCamera camera(parent->alembicXform(), m_name, m_time_sampling);
+ m_camera_schema = camera.getSchema();
+
+ m_custom_data_container = m_camera_schema.getUserProperties();
+ m_stereo_distance = OFloatProperty(m_custom_data_container, "stereoDistance", m_time_sampling);
+ m_eye_separation = OFloatProperty(m_custom_data_container, "eyeSeparation", m_time_sampling);
+}
+
+void AbcCameraWriter::do_write()
+{
+ Camera *cam = static_cast<Camera *>(m_object->data);
+
+ m_stereo_distance.set(cam->stereo.convergence_distance);
+ m_eye_separation.set(cam->stereo.interocular_distance);
+
+ const double apperture_x = cam->sensor_x / 10.0;
+ const double apperture_y = cam->sensor_y / 10.0;
+ const double film_aspect = apperture_x / apperture_y;
+
+ m_camera_sample.setFocalLength(cam->lens);
+ m_camera_sample.setHorizontalAperture(apperture_x);
+ m_camera_sample.setVerticalAperture(apperture_y);
+ m_camera_sample.setHorizontalFilmOffset(apperture_x * cam->shiftx);
+ m_camera_sample.setVerticalFilmOffset(apperture_y * cam->shifty * film_aspect);
+ m_camera_sample.setNearClippingPlane(cam->clipsta);
+ m_camera_sample.setFarClippingPlane(cam->clipend);
+
+ if (cam->dof_ob) {
+ Imath::V3f v(m_object->loc[0] - cam->dof_ob->loc[0],
+ m_object->loc[1] - cam->dof_ob->loc[1],
+ m_object->loc[2] - cam->dof_ob->loc[2]);
+ m_camera_sample.setFocusDistance(v.length());
+ }
+ else {
+ m_camera_sample.setFocusDistance(cam->gpu_dof.focus_distance);
+ }
+
+ /* Blender camera does not have an fstop param, so try to find a custom prop
+ * instead. */
+ m_camera_sample.setFStop(cam->gpu_dof.fstop);
+
+ m_camera_sample.setLensSqueezeRatio(1.0);
+ m_camera_schema.set(m_camera_sample);
+}
+
+/* ************************************************************************** */
+
+AbcCameraReader::AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ ICamera abc_cam(m_iobject, kWrapExisting);
+ m_schema = abc_cam.getSchema();
+
+ get_min_max_time(m_schema, m_min_time, m_max_time);
+}
+
+bool AbcCameraReader::valid() const
+{
+ return m_schema.valid();
+}
+
+void AbcCameraReader::readObjectData(Main *bmain, float time)
+{
+ Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, "abc_camera"));
+
+ ISampleSelector sample_sel(time);
+ CameraSample cam_sample;
+ m_schema.get(cam_sample, sample_sel);
+
+ ICompoundProperty customDataContainer = m_schema.getUserProperties();
+
+ if (customDataContainer.valid() &&
+ customDataContainer.getPropertyHeader("stereoDistance") &&
+ customDataContainer.getPropertyHeader("eyeSeparation"))
+ {
+ IFloatProperty convergence_plane(customDataContainer, "stereoDistance");
+ IFloatProperty eye_separation(customDataContainer, "eyeSeparation");
+
+ bcam->stereo.interocular_distance = eye_separation.getValue(sample_sel);
+ bcam->stereo.convergence_distance = convergence_plane.getValue(sample_sel);
+ }
+
+ const float lens = cam_sample.getFocalLength();
+ const float apperture_x = cam_sample.getHorizontalAperture();
+ const float apperture_y = cam_sample.getVerticalAperture();
+ const float h_film_offset = cam_sample.getHorizontalFilmOffset();
+ const float v_film_offset = cam_sample.getVerticalFilmOffset();
+ const float film_aspect = apperture_x / apperture_y;
+
+ bcam->lens = lens;
+ bcam->sensor_x = apperture_x * 10;
+ bcam->sensor_y = apperture_y * 10;
+ bcam->shiftx = h_film_offset / apperture_x;
+ bcam->shifty = v_film_offset / apperture_y / film_aspect;
+ bcam->clipsta = max_ff(0.1f, cam_sample.getNearClippingPlane());
+ bcam->clipend = cam_sample.getFarClippingPlane();
+ bcam->gpu_dof.focus_distance = cam_sample.getFocusDistance();
+ bcam->gpu_dof.fstop = cam_sample.getFStop();
+
+ BLI_strncpy(bcam->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1);
+
+ m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str());
+ m_object->data = bcam;
+}
diff --git a/source/blender/alembic/intern/abc_camera.h b/source/blender/alembic/intern/abc_camera.h
new file mode 100644
index 00000000000..fafb4d3eb39
--- /dev/null
+++ b/source/blender/alembic/intern/abc_camera.h
@@ -0,0 +1,61 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_CAMERA_H__
+#define __ABC_CAMERA_H__
+
+#include "abc_object.h"
+
+/* ************************************************************************** */
+
+class AbcCameraWriter : public AbcObjectWriter {
+ Alembic::AbcGeom::OCameraSchema m_camera_schema;
+ Alembic::AbcGeom::CameraSample m_camera_sample;
+ Alembic::AbcGeom::OCompoundProperty m_custom_data_container;
+ Alembic::AbcGeom::OFloatProperty m_stereo_distance;
+ Alembic::AbcGeom::OFloatProperty m_eye_separation;
+
+public:
+ AbcCameraWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings);
+
+private:
+ virtual void do_write();
+};
+
+/* ************************************************************************** */
+
+class AbcCameraReader : public AbcObjectReader {
+ Alembic::AbcGeom::ICameraSchema m_schema;
+
+public:
+ AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+};
+
+#endif /* __ABC_CAMERA_H__ */ \ No newline at end of file
diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc
new file mode 100644
index 00000000000..4e1e4e7e490
--- /dev/null
+++ b/source/blender/alembic/intern/abc_curves.cc
@@ -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) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#include "abc_curves.h"
+
+#include <cstdio>
+
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_curve.h"
+#include "BKE_object.h"
+
+#include "ED_curve.h"
+}
+
+using Alembic::Abc::IInt32ArrayProperty;
+using Alembic::Abc::Int32ArraySamplePtr;
+using Alembic::Abc::FloatArraySamplePtr;
+using Alembic::Abc::P3fArraySamplePtr;
+using Alembic::Abc::UcharArraySamplePtr;
+
+using Alembic::AbcGeom::ICurves;
+using Alembic::AbcGeom::ICurvesSchema;
+using Alembic::AbcGeom::IFloatGeomParam;
+using Alembic::AbcGeom::ISampleSelector;
+using Alembic::AbcGeom::kWrapExisting;
+using Alembic::AbcGeom::CurvePeriodicity;
+
+using Alembic::AbcGeom::OCurves;
+using Alembic::AbcGeom::OCurvesSchema;
+using Alembic::AbcGeom::ON3fGeomParam;
+using Alembic::AbcGeom::OV2fGeomParam;
+
+/* ************************************************************************** */
+
+AbcCurveWriter::AbcCurveWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings)
+ : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+{
+ OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
+ m_schema = curves.getSchema();
+}
+
+void AbcCurveWriter::do_write()
+{
+ Curve *curve = static_cast<Curve *>(m_object->data);
+
+ std::vector<Imath::V3f> verts;
+ std::vector<int32_t> vert_counts;
+ std::vector<float> widths;
+ std::vector<float> weights;
+ std::vector<float> knots;
+ std::vector<uint8_t> orders;
+ Imath::V3f temp_vert;
+
+ Alembic::AbcGeom::BasisType curve_basis;
+ Alembic::AbcGeom::CurveType curve_type;
+ Alembic::AbcGeom::CurvePeriodicity periodicity;
+
+ Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
+ for (; nurbs; nurbs = nurbs->next) {
+ if (nurbs->bp) {
+ curve_basis = Alembic::AbcGeom::kNoBasis;
+ curve_type = Alembic::AbcGeom::kLinear;
+
+ const int totpoint = nurbs->pntsu * nurbs->pntsv;
+
+ const BPoint *point = nurbs->bp;
+
+ for (int i = 0; i < totpoint; ++i, ++point) {
+ copy_zup_yup(temp_vert.getValue(), point->vec);
+ verts.push_back(temp_vert);
+ weights.push_back(point->vec[3]);
+ widths.push_back(point->radius);
+ }
+ }
+ else if (nurbs->bezt) {
+ curve_basis = Alembic::AbcGeom::kBezierBasis;
+ curve_type = Alembic::AbcGeom::kCubic;
+
+ const int totpoint = nurbs->pntsu;
+
+ const BezTriple *bezier = nurbs->bezt;
+
+ /* TODO(kevin): store info about handles, Alembic doesn't have this. */
+ for (int i = 0; i < totpoint; ++i, ++bezier) {
+ copy_zup_yup(temp_vert.getValue(), bezier->vec[1]);
+ verts.push_back(temp_vert);
+ widths.push_back(bezier->radius);
+ }
+ }
+
+ if ((nurbs->flagu & CU_NURB_ENDPOINT) != 0) {
+ periodicity = Alembic::AbcGeom::kNonPeriodic;
+ }
+ else if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) {
+ periodicity = Alembic::AbcGeom::kPeriodic;
+
+ /* Duplicate the start points to indicate that the curve is actually
+ * cyclic since other software need those.
+ */
+
+ for (int i = 0; i < nurbs->orderu; ++i) {
+ verts.push_back(verts[i]);
+ }
+ }
+
+ if (nurbs->knotsu != NULL) {
+ const size_t num_knots = KNOTSU(nurbs);
+
+ /* Add an extra knot at the beggining and end of the array since most apps
+ * require/expect them. */
+ knots.resize(num_knots + 2);
+
+ for (int i = 0; i < num_knots; ++i) {
+ knots[i + 1] = nurbs->knotsu[i];
+ }
+
+ if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) {
+ knots[0] = nurbs->knotsu[0];
+ knots[num_knots - 1] = nurbs->knotsu[num_knots - 1];
+ }
+ else {
+ knots[0] = (2.0f * nurbs->knotsu[0] - nurbs->knotsu[1]);
+ knots[num_knots - 1] = (2.0f * nurbs->knotsu[num_knots - 1] - nurbs->knotsu[num_knots - 2]);
+ }
+ }
+
+ orders.push_back(nurbs->orderu + 1);
+ vert_counts.push_back(verts.size());
+ }
+
+ Alembic::AbcGeom::OFloatGeomParam::Sample width_sample;
+ width_sample.setVals(widths);
+
+ m_sample = OCurvesSchema::Sample(verts,
+ vert_counts,
+ curve_type,
+ periodicity,
+ width_sample,
+ OV2fGeomParam::Sample(), /* UVs */
+ ON3fGeomParam::Sample(), /* normals */
+ curve_basis,
+ weights,
+ orders,
+ knots);
+
+ m_sample.setSelfBounds(bounds());
+ m_schema.set(m_sample);
+}
+
+/* ************************************************************************** */
+
+AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ ICurves abc_curves(object, kWrapExisting);
+ m_curves_schema = abc_curves.getSchema();
+
+ get_min_max_time(m_curves_schema, m_min_time, m_max_time);
+}
+
+bool AbcCurveReader::valid() const
+{
+ return m_curves_schema.valid();
+}
+
+void AbcCurveReader::readObjectData(Main *bmain, float time)
+{
+ Curve *cu = BKE_curve_add(bmain, m_data_name.c_str(), OB_CURVE);
+
+ cu->flag |= CU_DEFORM_FILL | CU_3D;
+ cu->actvert = CU_ACT_NONE;
+
+ m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_object_name.c_str());
+ m_object->data = cu;
+
+ read_curve_sample(cu, m_curves_schema, time);
+
+ if (has_animations(m_curves_schema, m_settings)) {
+ addCacheModifier();
+ }
+}
+
+/* ************************************************************************** */
+
+void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
+{
+ const ISampleSelector sample_sel(time);
+ ICurvesSchema::Sample smp = schema.getValue(sample_sel);
+ const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
+ const P3fArraySamplePtr positions = smp.getPositions();
+ const FloatArraySamplePtr weights = smp.getPositionWeights();
+ const FloatArraySamplePtr knots = smp.getKnots();
+ const CurvePeriodicity periodicity = smp.getWrap();
+ const UcharArraySamplePtr orders = smp.getOrders();
+
+ const IFloatGeomParam widths_param = schema.getWidthsParam();
+ FloatArraySamplePtr radiuses;
+
+ if (widths_param.valid()) {
+ IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
+ radiuses = wsample.getVals();
+ }
+
+ int knot_offset = 0;
+
+ size_t idx = 0;
+ for (size_t i = 0; i < num_vertices->size(); ++i) {
+ const int num_verts = (*num_vertices)[i];
+
+ Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
+ nu->resolu = cu->resolu;
+ nu->resolv = cu->resolv;
+ nu->pntsu = num_verts;
+ nu->pntsv = 1;
+ nu->flag |= CU_SMOOTH;
+
+ nu->orderu = num_verts;
+
+ if (smp.getType() == Alembic::AbcGeom::kCubic) {
+ nu->orderu = 3;
+ }
+ else if (orders && orders->size() > i) {
+ nu->orderu = static_cast<short>((*orders)[i] - 1);
+ }
+
+ if (periodicity == Alembic::AbcGeom::kNonPeriodic) {
+ nu->flagu |= CU_NURB_ENDPOINT;
+ }
+ else if (periodicity == Alembic::AbcGeom::kPeriodic) {
+ nu->flagu |= CU_NURB_CYCLIC;
+
+ /* Check the number of points which overlap, we don't have
+ * overlapping points in Blender, but other software do use them to
+ * indicate that a curve is actually cyclic. Usually the number of
+ * overlapping points is equal to the order/degree of the curve.
+ */
+
+ const int start = idx;
+ const int end = idx + num_verts;
+ int overlap = 0;
+
+ for (int j = start, k = end - nu->orderu; j < nu->orderu; ++j, ++k) {
+ const Imath::V3f &p1 = (*positions)[j];
+ const Imath::V3f &p2 = (*positions)[k];
+
+ if (p1 != p2) {
+ break;
+ }
+
+ ++overlap;
+ }
+
+ /* TODO: Special case, need to figure out how it coincides with knots. */
+ if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
+ overlap = 1;
+ }
+
+ /* There is no real cycles. */
+ if (overlap == 0) {
+ nu->flagu &= ~CU_NURB_CYCLIC;
+ nu->flagu |= CU_NURB_ENDPOINT;
+ }
+
+ nu->pntsu -= overlap;
+ }
+
+ const bool do_weights = (weights != NULL) && (weights->size() > 1);
+ float weight = 1.0f;
+
+ const bool do_radius = (radiuses != NULL) && (radiuses->size() > 1);
+ float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : 1.0f;
+
+ nu->type = CU_NURBS;
+
+ nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "abc_getnurb"));
+ BPoint *bp = nu->bp;
+
+ for (int j = 0; j < nu->pntsu; ++j, ++bp, ++idx) {
+ const Imath::V3f &pos = (*positions)[idx];
+
+ if (do_radius) {
+ radius = (*radiuses)[idx];
+ }
+
+ if (do_weights) {
+ weight = (*weights)[idx];
+ }
+
+ copy_yup_zup(bp->vec, pos.getValue());
+ bp->vec[3] = weight;
+ bp->f1 = SELECT;
+ bp->radius = radius;
+ bp->weight = 1.0f;
+ }
+
+ if (knots && knots->size() != 0) {
+ nu->knotsu = static_cast<float *>(MEM_callocN(KNOTSU(nu) * sizeof(float), "abc_setsplineknotsu"));
+
+ /* TODO: second check is temporary, for until the check for cycles is rock solid. */
+ if (periodicity == Alembic::AbcGeom::kPeriodic && (KNOTSU(nu) == knots->size() - 2)) {
+ /* Skip first and last knots. */
+ for (size_t i = 1; i < knots->size() - 1; ++i) {
+ nu->knotsu[i - 1] = (*knots)[knot_offset + i];
+ }
+ }
+ else {
+ /* TODO: figure out how to use the knots array from other
+ * software in this case. */
+ BKE_nurb_knot_calc_u(nu);
+ }
+
+ knot_offset += knots->size();
+ }
+ else {
+ BKE_nurb_knot_calc_u(nu);
+ }
+
+ BLI_addtail(BKE_curve_nurbs_get(cu), nu);
+ }
+}
diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_curves.h
new file mode 100644
index 00000000000..ee47f1931ea
--- /dev/null
+++ b/source/blender/alembic/intern/abc_curves.h
@@ -0,0 +1,65 @@
+/*
+ * ***** 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) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef __ABC_CURVES_H__
+#define __ABC_CURVES_H__
+
+#include "abc_object.h"
+
+struct Curve;
+
+/* ************************************************************************** */
+
+class AbcCurveWriter : public AbcObjectWriter {
+ Alembic::AbcGeom::OCurvesSchema m_schema;
+ Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
+
+public:
+ AbcCurveWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings);
+
+ void do_write();
+};
+
+/* ************************************************************************** */
+
+class AbcCurveReader : public AbcObjectReader {
+ Alembic::AbcGeom::ICurvesSchema m_curves_schema;
+
+public:
+ AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+};
+
+/* ************************************************************************** */
+
+void read_curve_sample(Curve *cu, const Alembic::AbcGeom::ICurvesSchema &schema, const float time);
+
+#endif /* __ABC_CURVES_H__ */ \ No newline at end of file
diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc
new file mode 100644
index 00000000000..ebf1b2ba96e
--- /dev/null
+++ b/source/blender/alembic/intern/abc_customdata.cc
@@ -0,0 +1,379 @@
+/*
+ * ***** 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) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#include "abc_customdata.h"
+
+#include <Alembic/AbcGeom/All.h>
+#include <algorithm>
+
+extern "C" {
+#include "DNA_customdata_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+}
+
+/* NOTE: for now only UVs and Vertex Colors are supported for streaming.
+ * Although Alembic only allows for a single UV layer per {I|O}Schema, and does
+ * not have a vertex color concept, there is a convention between DCCs to write
+ * such data in a way that lets other DCC know what they are for. See comments
+ * in the write code for the conventions. */
+
+using Alembic::AbcGeom::kVertexScope;
+using Alembic::AbcGeom::kFacevaryingScope;
+
+using Alembic::Abc::C4fArraySample;
+using Alembic::Abc::UInt32ArraySample;
+using Alembic::Abc::V2fArraySample;
+
+using Alembic::AbcGeom::OV2fGeomParam;
+using Alembic::AbcGeom::OC4fGeomParam;
+
+static void get_uvs(const CDStreamConfig &config,
+ std::vector<Imath::V2f> &uvs,
+ std::vector<uint32_t> &uvidx,
+ void *cd_data)
+{
+ MLoopUV *mloopuv_array = static_cast<MLoopUV *>(cd_data);
+
+ if (!mloopuv_array) {
+ return;
+ }
+
+ const int num_poly = config.totpoly;
+ MPoly *polygons = config.mpoly;
+
+ if (!config.pack_uvs) {
+ int cnt = 0;
+ uvidx.resize(config.totloop);
+ uvs.resize(config.totloop);
+
+ for (int i = 0; i < num_poly; ++i) {
+ MPoly &current_poly = polygons[i];
+ MLoopUV *loopuvpoly = mloopuv_array + current_poly.loopstart + current_poly.totloop;
+
+ for (int j = 0; j < current_poly.totloop; ++j, ++cnt) {
+ --loopuvpoly;
+
+ uvidx[cnt] = cnt;
+ uvs[cnt][0] = loopuvpoly->uv[0];
+ uvs[cnt][1] = loopuvpoly->uv[1];
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < num_poly; ++i) {
+ MPoly &current_poly = polygons[i];
+ MLoopUV *loopuvpoly = mloopuv_array + current_poly.loopstart + current_poly.totloop;
+
+ for (int j = 0; j < current_poly.totloop; ++j) {
+ loopuvpoly--;
+ Imath::V2f uv(loopuvpoly->uv[0], loopuvpoly->uv[1]);
+
+ std::vector<Imath::V2f>::iterator it = std::find(uvs.begin(), uvs.end(), uv);
+
+ if (it == uvs.end()) {
+ uvidx.push_back(uvs.size());
+ uvs.push_back(uv);
+ }
+ else {
+ uvidx.push_back(std::distance(uvs.begin(), it));
+ }
+ }
+ }
+ }
+}
+
+const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data)
+{
+ const int active_uvlayer = CustomData_get_active_layer(data, CD_MLOOPUV);
+
+ if (active_uvlayer < 0) {
+ return "";
+ }
+
+ void *cd_data = CustomData_get_layer_n(data, CD_MLOOPUV, active_uvlayer);
+
+ get_uvs(config, sample.uvs, sample.indices, cd_data);
+
+ return CustomData_get_layer_name(data, CD_MLOOPUV, active_uvlayer);
+}
+
+/* Convention to write UVs:
+ * - V2fGeomParam on the arbGeomParam
+ * - set scope as face varying
+ * - (optional due to its behaviour) tag as UV using Alembic::AbcGeom::SetIsUV
+ */
+static void write_uv(const OCompoundProperty &prop, const CDStreamConfig &config, void *data, const char *name)
+{
+ std::vector<uint32_t> indices;
+ std::vector<Imath::V2f> uvs;
+
+ get_uvs(config, uvs, indices, data);
+
+ if (indices.empty() || uvs.empty()) {
+ return;
+ }
+
+ OV2fGeomParam param(prop, name, true, kFacevaryingScope, 1);
+
+ OV2fGeomParam::Sample sample(
+ V2fArraySample(&uvs.front(), uvs.size()),
+ UInt32ArraySample(&indices.front(), indices.size()),
+ kFacevaryingScope);
+
+ param.set(sample);
+}
+
+/* Convention to write Vertex Colors:
+ * - C3fGeomParam/C4fGeomParam on the arbGeomParam
+ * - set scope as vertex varying
+ */
+static void write_mcol(const OCompoundProperty &prop, const CDStreamConfig &config, void *data, const char *name)
+{
+ const float cscale = 1.0f / 255.0f;
+ MPoly *polys = config.mpoly;
+ MLoop *mloops = config.mloop;
+ MCol *cfaces = static_cast<MCol *>(data);
+
+ std::vector<Imath::C4f> buffer(config.totvert);
+
+ Imath::C4f col;
+
+ for (int i = 0; i < config.totpoly; ++i) {
+ MPoly *p = &polys[i];
+ MCol *cface = &cfaces[p->loopstart + p->totloop];
+ MLoop *mloop = &mloops[p->loopstart + p->totloop];
+
+ for (int j = 0; j < p->totloop; ++j) {
+ cface--;
+ mloop--;
+
+ col[0] = cface->a * cscale;
+ col[1] = cface->r * cscale;
+ col[2] = cface->g * cscale;
+ col[3] = cface->b * cscale;
+
+ buffer[mloop->v] = col;
+ }
+ }
+
+ OC4fGeomParam param(prop, name, true, kFacevaryingScope, 1);
+
+ OC4fGeomParam::Sample sample(
+ C4fArraySample(&buffer.front(), buffer.size()),
+ kVertexScope);
+
+ param.set(sample);
+}
+
+void write_custom_data(const OCompoundProperty &prop, const CDStreamConfig &config, CustomData *data, int data_type)
+{
+ CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
+
+ if (!CustomData_has_layer(data, cd_data_type)) {
+ return;
+ }
+
+ const int active_layer = CustomData_get_active_layer(data, cd_data_type);
+ const int tot_layers = CustomData_number_of_layers(data, cd_data_type);
+
+ for (int i = 0; i < tot_layers; ++i) {
+ void *cd_data = CustomData_get_layer_n(data, cd_data_type, i);
+ const char *name = CustomData_get_layer_name(data, cd_data_type, i);
+
+ if (cd_data_type == CD_MLOOPUV) {
+ /* Already exported. */
+ if (i == active_layer) {
+ continue;
+ }
+
+ write_uv(prop, config, cd_data, name);
+ }
+ else if (cd_data_type == CD_MLOOPCOL) {
+ write_mcol(prop, config, cd_data, name);
+ }
+ }
+}
+
+/* ************************************************************************** */
+
+using Alembic::Abc::C3fArraySamplePtr;
+using Alembic::Abc::C4fArraySamplePtr;
+using Alembic::Abc::PropertyHeader;
+
+using Alembic::AbcGeom::IC3fGeomParam;
+using Alembic::AbcGeom::IC4fGeomParam;
+using Alembic::AbcGeom::IV2fGeomParam;
+
+static void read_mcols(const CDStreamConfig &config, void *data,
+ const C3fArraySamplePtr &c3f_ptr, const C4fArraySamplePtr &c4f_ptr)
+{
+ MCol *cfaces = static_cast<MCol *>(data);
+ MPoly *polys = config.mpoly;
+ MLoop *mloops = config.mloop;
+
+ if (c3f_ptr) {
+ for (int i = 0; i < config.totpoly; ++i) {
+ MPoly *p = &polys[i];
+ MCol *cface = &cfaces[p->loopstart + p->totloop];
+ MLoop *mloop = &mloops[p->loopstart + p->totloop];
+
+ for (int j = 0; j < p->totloop; ++j) {
+ cface--;
+ mloop--;
+ const Imath::C3f &color = (*c3f_ptr)[mloop->v];
+ cface->a = FTOCHAR(color[0]);
+ cface->r = FTOCHAR(color[1]);
+ cface->g = FTOCHAR(color[2]);
+ cface->b = 255;
+ }
+ }
+ }
+ else if (c4f_ptr) {
+ for (int i = 0; i < config.totpoly; ++i) {
+ MPoly *p = &polys[i];
+ MCol *cface = &cfaces[p->loopstart + p->totloop];
+ MLoop *mloop = &mloops[p->loopstart + p->totloop];
+
+ for (int j = 0; j < p->totloop; ++j) {
+ cface--;
+ mloop--;
+ const Imath::C4f &color = (*c4f_ptr)[mloop->v];
+ cface->a = FTOCHAR(color[0]);
+ cface->r = FTOCHAR(color[1]);
+ cface->g = FTOCHAR(color[2]);
+ cface->b = FTOCHAR(color[3]);
+ }
+ }
+ }
+}
+
+static void read_uvs(const CDStreamConfig &config, void *data,
+ const Alembic::AbcGeom::V2fArraySamplePtr &uvs,
+ const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
+{
+ MPoly *mpolys = config.mpoly;
+ MLoopUV *mloopuvs = static_cast<MLoopUV *>(data);
+
+ unsigned int uv_index, loop_index;
+
+ for (int i = 0; i < config.totpoly; ++i) {
+ MPoly &poly = mpolys[i];
+
+ for (int f = 0; f < poly.totloop; ++f) {
+ loop_index = poly.loopstart + f;
+ uv_index = (*indices)[loop_index];
+ const Imath::V2f &uv = (*uvs)[uv_index];
+
+ MLoopUV &loopuv = mloopuvs[loop_index];
+ loopuv.uv[0] = uv[0];
+ loopuv.uv[1] = uv[1];
+ }
+ }
+}
+
+static void read_custom_data_ex(const ICompoundProperty &prop,
+ const PropertyHeader &prop_header,
+ const CDStreamConfig &config,
+ const Alembic::Abc::ISampleSelector &iss,
+ int data_type)
+{
+ if (data_type == CD_MLOOPCOL) {
+ C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr();
+ C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr();
+
+ if (IC3fGeomParam::matches(prop_header)) {
+ IC3fGeomParam color_param(prop, prop_header.getName());
+ IC3fGeomParam::Sample sample;
+ color_param.getIndexed(sample, iss);
+
+ c3f_ptr = sample.getVals();
+ }
+ else if (IC4fGeomParam::matches(prop_header)) {
+ IC4fGeomParam color_param(prop, prop_header.getName());
+ IC4fGeomParam::Sample sample;
+ color_param.getIndexed(sample, iss);
+
+ c4f_ptr = sample.getVals();
+ }
+
+ void *cd_data = config.add_customdata_cb(config.user_data,
+ prop_header.getName().c_str(),
+ data_type);
+
+ read_mcols(config, cd_data, c3f_ptr, c4f_ptr);
+ }
+ else if (data_type == CD_MLOOPUV) {
+ IV2fGeomParam uv_param(prop, prop_header.getName());
+ IV2fGeomParam::Sample sample;
+ uv_param.getIndexed(sample, iss);
+
+ if (uv_param.getScope() != kFacevaryingScope) {
+ return;
+ }
+
+ void *cd_data = config.add_customdata_cb(config.user_data,
+ prop_header.getName().c_str(),
+ data_type);
+
+ read_uvs(config, cd_data, sample.getVals(), sample.getIndices());
+ }
+}
+
+void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss)
+{
+ if (!prop.valid()) {
+ return;
+ }
+
+ int num_uvs = 0;
+ int num_colors = 0;
+
+ const size_t num_props = prop.getNumProperties();
+
+ for (size_t i = 0; i < num_props; ++i) {
+ const Alembic::Abc::PropertyHeader &prop_header = prop.getPropertyHeader(i);
+
+ /* Read UVs according to convention. */
+ if (IV2fGeomParam::matches(prop_header) && Alembic::AbcGeom::isUV(prop_header)) {
+ if (++num_uvs > MAX_MTFACE) {
+ continue;
+ }
+
+ read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPUV);
+ continue;
+ }
+
+ /* Read vertex colors according to convention. */
+ if (IC3fGeomParam::matches(prop_header) || IC4fGeomParam::matches(prop_header)) {
+ if (++num_colors > MAX_MCOL) {
+ continue;
+ }
+
+ read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPCOL);
+ continue;
+ }
+ }
+}
diff --git a/source/blender/alembic/intern/abc_customdata.h b/source/blender/alembic/intern/abc_customdata.h
new file mode 100644
index 00000000000..3b16c0d9796
--- /dev/null
+++ b/source/blender/alembic/intern/abc_customdata.h
@@ -0,0 +1,93 @@
+/*
+ * ***** 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) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef __ABC_CUSTOMDATA_H__
+#define __ABC_CUSTOMDATA_H__
+
+#include <Alembic/Abc/All.h>
+
+struct CustomData;
+struct MLoop;
+struct MLoopUV;
+struct MPoly;
+struct MVert;
+
+using Alembic::Abc::ICompoundProperty;
+using Alembic::Abc::OCompoundProperty;
+
+struct UVSample {
+ std::vector<Imath::V2f> uvs;
+ std::vector<uint32_t> indices;
+};
+
+struct CDStreamConfig {
+ MLoop *mloop;
+ int totloop;
+
+ MPoly *mpoly;
+ int totpoly;
+
+ MVert *mvert;
+ int totvert;
+
+ MLoopUV *mloopuv;
+
+ CustomData *loopdata;
+
+ bool pack_uvs;
+
+ /* TODO(kevin): might need a better way to handle adding and/or updating
+ * custom datas such that it updates the custom data holder and its pointers
+ * properly. */
+ void *user_data;
+ void *(*add_customdata_cb)(void *user_data, const char *name, int data_type);
+
+ CDStreamConfig()
+ : mloop(NULL)
+ , totloop(0)
+ , mpoly(NULL)
+ , totpoly(0)
+ , totvert(0)
+ , pack_uvs(false)
+ , user_data(NULL)
+ , add_customdata_cb(NULL)
+ {}
+};
+
+/* Get the UVs for the main UV property on a OSchema.
+ * Returns the name of the UV layer.
+ *
+ * For now the active layer is used, maybe needs a better way to choose this. */
+const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data);
+
+void write_custom_data(const OCompoundProperty &prop,
+ const CDStreamConfig &config,
+ CustomData *data,
+ int data_type);
+
+void read_custom_data(const ICompoundProperty &prop,
+ const CDStreamConfig &config,
+ const Alembic::Abc::ISampleSelector &iss);
+
+#endif /* __ABC_CUSTOMDATA_H__ */
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
new file mode 100644
index 00000000000..127e8853789
--- /dev/null
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -0,0 +1,600 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_exporter.h"
+
+#include <cmath>
+
+#ifdef WITH_ALEMBIC_HDF5
+# include <Alembic/AbcCoreHDF5/All.h>
+#endif
+
+#include <Alembic/AbcCoreOgawa/All.h>
+
+#include "abc_camera.h"
+#include "abc_curves.h"
+#include "abc_hair.h"
+#include "abc_mesh.h"
+#include "abc_nurbs.h"
+#include "abc_points.h"
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX */
+
+#include "BLI_string.h"
+
+#ifdef WIN32
+/* needed for MSCV because of snprintf from BLI_string */
+# include "BLI_winstuff.h"
+#endif
+
+#include "BKE_anim.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_particle.h"
+#include "BKE_scene.h"
+}
+
+using Alembic::Abc::TimeSamplingPtr;
+using Alembic::Abc::OBox3dProperty;
+
+/* ************************************************************************** */
+
+ExportSettings::ExportSettings()
+ : scene(NULL)
+ , selected_only(false)
+ , visible_layers_only(false)
+ , renderable_only(false)
+ , frame_start(1)
+ , frame_end(1)
+ , frame_step_xform(1)
+ , frame_step_shape(1)
+ , shutter_open(0.0)
+ , shutter_close(1.0)
+ , global_scale(1.0f)
+ , flatten_hierarchy(false)
+ , export_normals(false)
+ , export_uvs(false)
+ , export_vcols(false)
+ , export_face_sets(false)
+ , export_vweigths(false)
+ , apply_subdiv(false)
+ , use_subdiv_schema(false)
+ , export_child_hairs(true)
+ , export_ogawa(true)
+ , pack_uv(false)
+ , do_convert_axis(false)
+{}
+
+static bool object_is_smoke_sim(Object *ob)
+{
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke);
+
+ if (md) {
+ SmokeModifierData *smd = reinterpret_cast<SmokeModifierData *>(md);
+ return (smd->type == MOD_SMOKE_TYPE_DOMAIN);
+ }
+
+ return false;
+}
+
+static bool object_is_shape(Object *ob)
+{
+ switch (ob->type) {
+ case OB_MESH:
+ if (object_is_smoke_sim(ob)) {
+ return false;
+ }
+
+ return true;
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_CAMERA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool export_object(const ExportSettings * const settings, Object *ob)
+{
+ if (settings->selected_only && !parent_selected(ob)) {
+ return false;
+ }
+
+ if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) {
+ return false;
+ }
+
+ if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) {
+ return false;
+ }
+
+ return true;
+}
+
+/* ************************************************************************** */
+
+AbcExporter::AbcExporter(Scene *scene, const char *filename, ExportSettings &settings)
+ : m_settings(settings)
+ , m_filename(filename)
+ , m_trans_sampling_index(0)
+ , m_shape_sampling_index(0)
+ , m_scene(scene)
+{}
+
+AbcExporter::~AbcExporter()
+{
+ std::map<std::string, AbcTransformWriter*>::iterator it, e;
+ for (it = m_xforms.begin(), e = m_xforms.end(); it != e; ++it) {
+ delete it->second;
+ }
+
+ for (int i = 0, e = m_shapes.size(); i != e; ++i) {
+ delete m_shapes[i];
+ }
+}
+
+void AbcExporter::getShutterSamples(double step, bool time_relative,
+ std::vector<double> &samples)
+{
+ samples.clear();
+
+ const double time_factor = time_relative ? m_scene->r.frs_sec : 1.0;
+ const double shutter_open = m_settings.shutter_open;
+ const double shutter_close = m_settings.shutter_close;
+
+ /* sample all frame */
+ if (shutter_open == 0.0 && shutter_close == 1.0) {
+ for (double t = 0; t < 1.0; t += step) {
+ samples.push_back(t / time_factor);
+ }
+ }
+ else {
+ /* sample between shutter open & close */
+ const int nsamples = std::max((1.0 / step) - 1.0, 1.0);
+ const double time_inc = (shutter_close - shutter_open) / nsamples;
+
+ for (double t = shutter_open; t <= shutter_close; t += time_inc) {
+ samples.push_back(t / time_factor);
+ }
+ }
+}
+
+Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step)
+{
+ TimeSamplingPtr time_sampling;
+ std::vector<double> samples;
+
+ if (m_settings.frame_start == m_settings.frame_end) {
+ time_sampling.reset(new Alembic::Abc::TimeSampling());
+ return time_sampling;
+ }
+
+ getShutterSamples(step, true, samples);
+
+ Alembic::Abc::TimeSamplingType ts(static_cast<uint32_t>(samples.size()), 1.0 / m_scene->r.frs_sec);
+ time_sampling.reset(new Alembic::Abc::TimeSampling(ts, samples));
+
+ return time_sampling;
+}
+
+void AbcExporter::getFrameSet(double step, std::set<double> &frames)
+{
+ frames.clear();
+
+ std::vector<double> shutter_samples;
+
+ getShutterSamples(step, false, shutter_samples);
+
+ for (int frame = m_settings.frame_start; frame <= m_settings.frame_end; ++frame) {
+ for (int j = 0, e = shutter_samples.size(); j < e; ++j) {
+ frames.insert(frame + shutter_samples[j]);
+ }
+ }
+}
+
+void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
+{
+ std::string scene_name;
+
+ if (bmain->name[0] != '\0') {
+ char scene_file_name[FILE_MAX];
+ BLI_strncpy(scene_file_name, bmain->name, FILE_MAX);
+ scene_name = scene_file_name;
+ }
+ else {
+ scene_name = "untitled";
+ }
+
+ Scene *scene = m_scene;
+ const int fps = FPS;
+ char buf[16];
+ snprintf(buf, 15, "%d", fps);
+ const std::string str_fps = buf;
+
+ Alembic::AbcCoreAbstract::MetaData md;
+ md.set("FramesPerTimeUnit", str_fps);
+
+ Alembic::Abc::Argument arg(md);
+
+#ifdef WITH_ALEMBIC_HDF5
+ if (!m_settings.export_ogawa) {
+ m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreHDF5::WriteArchive(),
+ m_filename,
+ "Blender",
+ scene_name,
+ Alembic::Abc::ErrorHandler::kThrowPolicy,
+ arg);
+ }
+ else
+#endif
+ {
+ m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreOgawa::WriteArchive(),
+ m_filename,
+ "Blender",
+ scene_name,
+ Alembic::Abc::ErrorHandler::kThrowPolicy,
+ arg);
+ }
+
+ /* Create time samplings for transforms and shapes. */
+
+ TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_step_xform);
+
+ m_trans_sampling_index = m_archive.addTimeSampling(*trans_time);
+
+ TimeSamplingPtr shape_time;
+
+ if ((m_settings.frame_step_shape == m_settings.frame_step_xform) ||
+ (m_settings.frame_start == m_settings.frame_end))
+ {
+ shape_time = trans_time;
+ m_shape_sampling_index = m_trans_sampling_index;
+ }
+ else {
+ shape_time = createTimeSampling(m_settings.frame_step_shape);
+ m_shape_sampling_index = m_archive.addTimeSampling(*shape_time);
+ }
+
+ OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_archive, m_trans_sampling_index);
+
+ if (m_settings.flatten_hierarchy) {
+ createTransformWritersFlat();
+ }
+ else {
+ createTransformWritersHierarchy(bmain->eval_ctx);
+ }
+
+ createShapeWriters(bmain->eval_ctx);
+
+ /* Make a list of frames to export. */
+
+ std::set<double> xform_frames;
+ getFrameSet(m_settings.frame_step_xform, xform_frames);
+
+ std::set<double> shape_frames;
+ getFrameSet(m_settings.frame_step_shape, shape_frames);
+
+ /* Merge all frames needed. */
+
+ std::set<double> frames(xform_frames);
+ frames.insert(shape_frames.begin(), shape_frames.end());
+
+ /* Export all frames. */
+
+ std::set<double>::const_iterator begin = frames.begin();
+ std::set<double>::const_iterator end = frames.end();
+
+ const float size = static_cast<float>(frames.size());
+ size_t i = 0;
+
+ for (; begin != end; ++begin) {
+ progress = (++i / size);
+
+ if (G.is_break) {
+ was_canceled = true;
+ break;
+ }
+
+ double f = *begin;
+ setCurrentFrame(bmain, f);
+
+ if (shape_frames.count(f) != 0) {
+ for (int i = 0, e = m_shapes.size(); i != e; ++i) {
+ m_shapes[i]->write();
+ }
+ }
+
+ if (xform_frames.count(f) == 0) {
+ continue;
+ }
+
+ std::map<std::string, AbcTransformWriter *>::iterator xit, xe;
+ for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) {
+ xit->second->write();
+ }
+
+ /* Save the archive 's bounding box. */
+ Imath::Box3d bounds;
+
+ for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) {
+ Imath::Box3d box = xit->second->bounds();
+ bounds.extendBy(box);
+ }
+
+ archive_bounds_prop.set(bounds);
+ }
+}
+
+void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx)
+{
+ Base *base = static_cast<Base *>(m_scene->base.first);
+
+ while (base) {
+ Object *ob = base->object;
+
+ if (export_object(&m_settings, ob)) {
+ switch(ob->type) {
+ case OB_LAMP:
+ case OB_LATTICE:
+ case OB_MBALL:
+ case OB_SPEAKER:
+ /* We do not export transforms for objects of these classes. */
+ break;
+
+ default:
+ exploreTransform(eval_ctx, ob, ob->parent, NULL);
+ }
+ }
+
+ base = base->next;
+ }
+}
+
+void AbcExporter::createTransformWritersFlat()
+{
+ Base *base = static_cast<Base *>(m_scene->base.first);
+
+ while (base) {
+ Object *ob = base->object;
+
+ if (export_object(&m_settings, ob) && object_is_shape(ob)) {
+ std::string name = get_id_name(ob);
+ m_xforms[name] = new AbcTransformWriter(ob, m_archive.getTop(), 0, m_trans_sampling_index, m_settings);
+ }
+
+ base = base->next;
+ }
+}
+
+void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent)
+{
+ createTransformWriter(ob, parent, dupliObParent);
+
+ ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
+
+ if (lb) {
+ DupliObject *link = static_cast<DupliObject *>(lb->first);
+ Object *dupli_ob = NULL;
+ Object *dupli_parent = NULL;
+
+ while (link) {
+ if (link->type == OB_DUPLIGROUP) {
+ dupli_ob = link->ob;
+ dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob;
+
+ exploreTransform(eval_ctx, dupli_ob, dupli_parent, ob);
+ }
+
+ link = link->next;
+ }
+ }
+
+ free_object_duplilist(lb);
+}
+
+void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent)
+{
+ const std::string name = get_object_dag_path_name(ob, dupliObParent);
+
+ /* check if we have already created a transform writer for this object */
+ if (m_xforms.find(name) != m_xforms.end()){
+ std::cerr << "xform " << name << " already exists\n";
+ return;
+ }
+
+ AbcTransformWriter *parent_xform = NULL;
+
+ if (parent) {
+ const std::string parentname = get_object_dag_path_name(parent, dupliObParent);
+ parent_xform = getXForm(parentname);
+
+ if (!parent_xform) {
+ if (parent->parent) {
+ createTransformWriter(parent, parent->parent, dupliObParent);
+ }
+ else {
+ createTransformWriter(parent, dupliObParent, dupliObParent);
+ }
+
+ parent_xform = getXForm(parentname);
+ }
+ }
+
+ if (parent_xform) {
+ m_xforms[name] = new AbcTransformWriter(ob, parent_xform->alembicXform(), parent_xform, m_trans_sampling_index, m_settings);
+ m_xforms[name]->setParent(parent);
+ }
+ else {
+ m_xforms[name] = new AbcTransformWriter(ob, m_archive.getTop(), NULL, m_trans_sampling_index, m_settings);
+ }
+}
+
+void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx)
+{
+ Base *base = static_cast<Base *>(m_scene->base.first);
+
+ while (base) {
+ Object *ob = base->object;
+ exploreObject(eval_ctx, ob, NULL);
+
+ base = base->next;
+ }
+}
+
+void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent)
+{
+ ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
+
+ createShapeWriter(ob, dupliObParent);
+
+ if (lb) {
+ DupliObject *dupliob = static_cast<DupliObject *>(lb->first);
+
+ while (dupliob) {
+ if (dupliob->type == OB_DUPLIGROUP) {
+ exploreObject(eval_ctx, dupliob->ob, ob);
+ }
+
+ dupliob = dupliob->next;
+ }
+ }
+
+ free_object_duplilist(lb);
+}
+
+void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
+{
+ if (!object_is_shape(ob)) {
+ return;
+ }
+
+ if (!export_object(&m_settings, ob)) {
+ return;
+ }
+
+ std::string name;
+
+ if (m_settings.flatten_hierarchy) {
+ name = get_id_name(ob);
+ }
+ else {
+ name = get_object_dag_path_name(ob, dupliObParent);
+ }
+
+ AbcTransformWriter *xform = getXForm(name);
+
+ if (!xform) {
+ std::cerr << __func__ << ": xform " << name << " is NULL\n";
+ return;
+ }
+
+ ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first);
+
+ for (; psys; psys = psys->next) {
+ if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) {
+ continue;
+ }
+
+ if (psys->part->type == PART_HAIR) {
+ m_settings.export_child_hairs = true;
+ m_shapes.push_back(new AbcHairWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
+ }
+ else if (psys->part->type == PART_EMITTER) {
+ m_shapes.push_back(new AbcPointsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
+ }
+ }
+
+ switch(ob->type) {
+ case OB_MESH:
+ {
+ Mesh *me = static_cast<Mesh *>(ob->data);
+
+ if (!me || me->totvert == 0) {
+ return;
+ }
+
+ m_shapes.push_back(new AbcMeshWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ break;
+ }
+ case OB_SURF:
+ {
+ Curve *cu = static_cast<Curve *>(ob->data);
+
+ if (!cu) {
+ return;
+ }
+
+ m_shapes.push_back(new AbcNurbsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ break;
+ }
+ case OB_CURVE:
+ {
+ Curve *cu = static_cast<Curve *>(ob->data);
+
+ if (!cu) {
+ return;
+ }
+
+ m_shapes.push_back(new AbcCurveWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ break;
+ }
+ case OB_CAMERA:
+ {
+ Camera *cam = static_cast<Camera *>(ob->data);
+
+ if (cam->type == CAM_PERSP) {
+ m_shapes.push_back(new AbcCameraWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ }
+
+ break;
+ }
+ }
+}
+
+AbcTransformWriter *AbcExporter::getXForm(const std::string &name)
+{
+ std::map<std::string, AbcTransformWriter *>::iterator it = m_xforms.find(name);
+
+ if (it == m_xforms.end()) {
+ return NULL;
+ }
+
+ return it->second;
+}
+
+void AbcExporter::setCurrentFrame(Main *bmain, double t)
+{
+ m_scene->r.cfra = std::floor(t);
+ m_scene->r.subframe = t - m_scene->r.cfra;
+ BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, m_scene, m_scene->lay);
+}
diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h
new file mode 100644
index 00000000000..070eb9ea81a
--- /dev/null
+++ b/source/blender/alembic/intern/abc_exporter.h
@@ -0,0 +1,112 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_EXPORTER_H__
+#define __ABC_EXPORTER_H__
+
+#include <Alembic/Abc/All.h>
+#include <map>
+#include <set>
+#include <vector>
+
+class AbcObjectWriter;
+class AbcTransformWriter;
+
+struct EvaluationContext;
+struct Main;
+struct Object;
+struct Scene;
+
+struct ExportSettings {
+ ExportSettings();
+
+ Scene *scene;
+
+ bool selected_only;
+ bool visible_layers_only;
+ bool renderable_only;
+
+ double frame_start, frame_end;
+ double frame_step_xform;
+ double frame_step_shape;
+ double shutter_open;
+ double shutter_close;
+ float global_scale;
+
+ bool flatten_hierarchy;
+
+ bool export_normals;
+ bool export_uvs;
+ bool export_vcols;
+ bool export_face_sets;
+ bool export_vweigths;
+
+ bool apply_subdiv;
+ bool use_subdiv_schema;
+ bool export_child_hairs;
+ bool export_ogawa;
+ bool pack_uv;
+
+ bool do_convert_axis;
+ float convert_matrix[3][3];
+};
+
+class AbcExporter {
+ ExportSettings &m_settings;
+
+ const char *m_filename;
+
+ Alembic::Abc::OArchive m_archive;
+ unsigned int m_trans_sampling_index, m_shape_sampling_index;
+
+ Scene *m_scene;
+
+ std::map<std::string, AbcTransformWriter *> m_xforms;
+ std::vector<AbcObjectWriter *> m_shapes;
+
+public:
+ AbcExporter(Scene *scene, const char *filename, ExportSettings &settings);
+ ~AbcExporter();
+
+ void operator()(Main *bmain, float &progress, bool &was_canceled);
+
+private:
+ void getShutterSamples(double step, bool time_relative, std::vector<double> &samples);
+
+ Alembic::Abc::TimeSamplingPtr createTimeSampling(double step);
+
+ void getFrameSet(double step, std::set<double> &frames);
+
+ void createTransformWritersHierarchy(EvaluationContext *eval_ctx);
+ void createTransformWritersFlat();
+ void createTransformWriter(Object *ob, Object *parent, Object *dupliObParent);
+ void exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent = NULL);
+ void exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent);
+ void createShapeWriters(EvaluationContext *eval_ctx);
+ void createShapeWriter(Object *ob, Object *dupliObParent);
+
+ AbcTransformWriter *getXForm(const std::string &name);
+
+ void setCurrentFrame(Main *bmain, double t);
+};
+
+#endif /* __ABC_EXPORTER_H__ */
diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc
new file mode 100644
index 00000000000..45bf9b7ab8a
--- /dev/null
+++ b/source/blender/alembic/intern/abc_hair.cc
@@ -0,0 +1,290 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_hair.h"
+
+#include <cstdio>
+
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "DNA_modifier_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math_geom.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+}
+
+using Alembic::Abc::P3fArraySamplePtr;
+
+using Alembic::AbcGeom::OCurves;
+using Alembic::AbcGeom::OCurvesSchema;
+using Alembic::AbcGeom::ON3fGeomParam;
+using Alembic::AbcGeom::OV2fGeomParam;
+
+/* ************************************************************************** */
+
+AbcHairWriter::AbcHairWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings,
+ ParticleSystem *psys)
+ : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+{
+ m_psys = psys;
+
+ OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
+ m_schema = curves.getSchema();
+}
+
+void AbcHairWriter::do_write()
+{
+ if (!m_psys) {
+ return;
+ }
+
+ ParticleSystemModifierData *psmd = psys_get_modifier(m_object, m_psys);
+
+ if (!psmd->dm_final) {
+ return;
+ }
+
+ DerivedMesh *dm = mesh_create_derived_view(m_scene, m_object, CD_MASK_MESH);
+ DM_ensure_tessface(dm);
+ DM_update_tessface_data(dm);
+
+ std::vector<Imath::V3f> verts;
+ std::vector<int32_t> hvertices;
+ std::vector<Imath::V2f> uv_values;
+ std::vector<Imath::V3f> norm_values;
+
+ if (m_psys->pathcache) {
+ ParticleSettings *part = m_psys->part;
+
+ write_hair_sample(dm, part, verts, norm_values, uv_values, hvertices);
+
+ if (m_settings.export_child_hairs && m_psys->childcache) {
+ write_hair_child_sample(dm, part, verts, norm_values, uv_values, hvertices);
+ }
+ }
+
+ dm->release(dm);
+
+ Alembic::Abc::P3fArraySample iPos(verts);
+ m_sample = OCurvesSchema::Sample(iPos, hvertices);
+ m_sample.setBasis(Alembic::AbcGeom::kNoBasis);
+ m_sample.setType(Alembic::AbcGeom::kLinear);
+ m_sample.setWrap(Alembic::AbcGeom::kNonPeriodic);
+
+ if (!uv_values.empty()) {
+ OV2fGeomParam::Sample uv_smp;
+ uv_smp.setVals(uv_values);
+ m_sample.setUVs(uv_smp);
+ }
+
+ if (!norm_values.empty()) {
+ ON3fGeomParam::Sample norm_smp;
+ norm_smp.setVals(norm_values);
+ m_sample.setNormals(norm_smp);
+ }
+
+ m_sample.setSelfBounds(bounds());
+ m_schema.set(m_sample);
+}
+
+void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
+ ParticleSettings *part,
+ std::vector<Imath::V3f> &verts,
+ std::vector<Imath::V3f> &norm_values,
+ std::vector<Imath::V2f> &uv_values,
+ std::vector<int32_t> &hvertices)
+{
+ /* Get untransformed vertices, there's a xform under the hair. */
+ float inv_mat[4][4];
+ invert_m4_m4_safe(inv_mat, m_object->obmat);
+
+ MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
+ MFace *mface = dm->getTessFaceArray(dm);
+ MVert *mverts = dm->getVertArray(dm);
+
+ if (!mtface || !mface) {
+ std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
+ }
+
+ ParticleData * pa = m_psys->particles;
+ int k;
+
+ ParticleCacheKey **cache = m_psys->pathcache;
+ ParticleCacheKey *path;
+ float normal[3];
+ Imath::V3f tmp_nor;
+
+ for (int p = 0; p < m_psys->totpart; ++p, ++pa) {
+ /* underlying info for faces-only emission */
+ path = cache[p];
+
+ if (part->from == PART_FROM_FACE && mtface) {
+ const int num = pa->num_dmcache >= 0 ? pa->num_dmcache : pa->num;
+
+ if (num < dm->getNumTessFaces(dm)) {
+ MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
+ MTFace *tface = mtface + num;
+
+ if (mface) {
+ float r_uv[2], mapfw[4], vec[3];
+
+ psys_interpolate_uvs(tface, face->v4, pa->fuv, r_uv);
+ uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
+
+ psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL, NULL);
+
+ copy_zup_yup(tmp_nor.getValue(), normal);
+ norm_values.push_back(tmp_nor);
+ }
+ }
+ else {
+ std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, dm->getNumTessFaces(dm));
+ }
+ }
+ else if (part->from == PART_FROM_VERT && mtface) {
+ /* vertex id */
+ const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num;
+
+ /* iterate over all faces to find a corresponding underlying UV */
+ for (int n = 0; n < dm->getNumTessFaces(dm); ++n) {
+ MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, n, CD_MFACE));
+ MTFace *tface = mtface + n;
+ unsigned int vtx[4];
+ vtx[0] = face->v1;
+ vtx[1] = face->v2;
+ vtx[2] = face->v3;
+ vtx[3] = face->v4;
+ bool found = false;
+
+ for (int o = 0; o < 4; ++o) {
+ if (o > 2 && vtx[o] == 0) {
+ break;
+ }
+
+ if (vtx[o] == num) {
+ uv_values.push_back(Imath::V2f(tface->uv[o][0], tface->uv[o][1]));
+
+ MVert *mv = mverts + vtx[o];
+
+ normal_short_to_float_v3(normal, mv->no);
+ copy_zup_yup(tmp_nor.getValue(), normal);
+ norm_values.push_back(tmp_nor);
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ break;
+ }
+ }
+ }
+
+ int steps = path->segments + 1;
+ hvertices.push_back(steps);
+
+ for (k = 0; k < steps; ++k) {
+ float vert[3];
+ copy_v3_v3(vert, path->co);
+ mul_m4_v3(inv_mat, vert);
+
+ /* Convert Z-up to Y-up. */
+ verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
+
+ ++path;
+ }
+ }
+}
+
+void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
+ ParticleSettings *part,
+ std::vector<Imath::V3f> &verts,
+ std::vector<Imath::V3f> &norm_values,
+ std::vector<Imath::V2f> &uv_values,
+ std::vector<int32_t> &hvertices)
+{
+ /* Get untransformed vertices, there's a xform under the hair. */
+ float inv_mat[4][4];
+ invert_m4_m4_safe(inv_mat, m_object->obmat);
+
+ MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
+ MFace *mface = dm->getTessFaceArray(dm);
+ MVert *mverts = dm->getVertArray(dm);
+
+ if (!mtface || !mface) {
+ std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
+ }
+
+ ParticleCacheKey **cache = m_psys->childcache;
+ ParticleCacheKey *path;
+
+ ChildParticle *pc = m_psys->child;
+
+ for (int p = 0; p < m_psys->totchild; ++p, ++pc) {
+ path = cache[p];
+
+ if (part->from == PART_FROM_FACE) {
+ const int num = pc->num;
+
+ MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
+ MTFace *tface = mtface + num;
+
+ if (mface && mtface) {
+ float r_uv[2], tmpnor[3], mapfw[4], vec[3];
+
+ psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
+ uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
+
+ psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, tmpnor, NULL, NULL, NULL, NULL);
+
+ /* Convert Z-up to Y-up. */
+ norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1]));
+ }
+ }
+
+ int steps = path->segments + 1;
+ hvertices.push_back(steps);
+
+ for (int k = 0; k < steps; ++k) {
+ float vert[3];
+ copy_v3_v3(vert, path->co);
+ mul_m4_v3(inv_mat, vert);
+
+ /* Convert Z-up to Y-up. */
+ verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
+
+ ++path;
+ }
+ }
+}
diff --git a/source/blender/alembic/intern/abc_hair.h b/source/blender/alembic/intern/abc_hair.h
new file mode 100644
index 00000000000..d132b60be12
--- /dev/null
+++ b/source/blender/alembic/intern/abc_hair.h
@@ -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.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_HAIR_H__
+#define __ABC_HAIR_H__
+
+#include "abc_object.h"
+
+struct DerivedMesh;
+struct ParticleSettings;
+struct ParticleSystem;
+
+/* ************************************************************************** */
+
+class AbcHairWriter : public AbcObjectWriter {
+ ParticleSystem *m_psys;
+
+ Alembic::AbcGeom::OCurvesSchema m_schema;
+ Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
+
+public:
+ AbcHairWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings,
+ ParticleSystem *psys);
+
+private:
+ virtual void do_write();
+
+ void write_hair_sample(DerivedMesh *dm,
+ ParticleSettings *part,
+ std::vector<Imath::V3f> &verts,
+ std::vector<Imath::V3f> &norm_values,
+ std::vector<Imath::V2f> &uv_values,
+ std::vector<int32_t> &hvertices);
+
+ void write_hair_child_sample(DerivedMesh *dm,
+ ParticleSettings *part,
+ std::vector<Imath::V3f> &verts,
+ std::vector<Imath::V3f> &norm_values,
+ std::vector<Imath::V2f> &uv_values,
+ std::vector<int32_t> &hvertices);
+};
+
+#endif /* __ABC_HAIR_H__ */
diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
new file mode 100644
index 00000000000..f1c7b6b3aa3
--- /dev/null
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -0,0 +1,1213 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_mesh.h"
+
+#include <algorithm>
+
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_fluidsim.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math_geom.h"
+#include "BLI_string.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+}
+
+using Alembic::Abc::FloatArraySample;
+using Alembic::Abc::ICompoundProperty;
+using Alembic::Abc::Int32ArraySample;
+using Alembic::Abc::Int32ArraySamplePtr;
+using Alembic::Abc::P3fArraySamplePtr;
+using Alembic::Abc::V2fArraySample;
+using Alembic::Abc::V3fArraySample;
+using Alembic::Abc::C4fArraySample;
+
+using Alembic::AbcGeom::IFaceSet;
+using Alembic::AbcGeom::IFaceSetSchema;
+using Alembic::AbcGeom::IObject;
+using Alembic::AbcGeom::IPolyMesh;
+using Alembic::AbcGeom::IPolyMeshSchema;
+using Alembic::AbcGeom::ISampleSelector;
+using Alembic::AbcGeom::ISubD;
+using Alembic::AbcGeom::ISubDSchema;
+using Alembic::AbcGeom::IV2fGeomParam;
+
+using Alembic::AbcGeom::OArrayProperty;
+using Alembic::AbcGeom::OBoolProperty;
+using Alembic::AbcGeom::OC3fArrayProperty;
+using Alembic::AbcGeom::OC3fGeomParam;
+using Alembic::AbcGeom::OC4fGeomParam;
+using Alembic::AbcGeom::OCompoundProperty;
+using Alembic::AbcGeom::OFaceSet;
+using Alembic::AbcGeom::OFaceSetSchema;
+using Alembic::AbcGeom::OFloatGeomParam;
+using Alembic::AbcGeom::OInt32GeomParam;
+using Alembic::AbcGeom::ON3fArrayProperty;
+using Alembic::AbcGeom::ON3fGeomParam;
+using Alembic::AbcGeom::OPolyMesh;
+using Alembic::AbcGeom::OPolyMeshSchema;
+using Alembic::AbcGeom::OSubD;
+using Alembic::AbcGeom::OSubDSchema;
+using Alembic::AbcGeom::OV2fGeomParam;
+using Alembic::AbcGeom::OV3fGeomParam;
+
+using Alembic::AbcGeom::kFacevaryingScope;
+using Alembic::AbcGeom::kVaryingScope;
+using Alembic::AbcGeom::kVertexScope;
+using Alembic::AbcGeom::kWrapExisting;
+using Alembic::AbcGeom::UInt32ArraySample;
+using Alembic::AbcGeom::N3fArraySamplePtr;
+using Alembic::AbcGeom::IN3fGeomParam;
+
+/* ************************************************************************** */
+
+/* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */
+
+static void get_vertices(DerivedMesh *dm, std::vector<Imath::V3f> &points)
+{
+ points.clear();
+ points.resize(dm->getNumVerts(dm));
+
+ MVert *verts = dm->getVertArray(dm);
+
+ for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
+ copy_zup_yup(points[i].getValue(), verts[i].co);
+ }
+}
+
+static void get_topology(DerivedMesh *dm,
+ std::vector<int32_t> &poly_verts,
+ std::vector<int32_t> &loop_counts,
+ bool &smooth_normal)
+{
+ const int num_poly = dm->getNumPolys(dm);
+ const int num_loops = dm->getNumLoops(dm);
+ MLoop *mloop = dm->getLoopArray(dm);
+ MPoly *mpoly = dm->getPolyArray(dm);
+
+ poly_verts.clear();
+ loop_counts.clear();
+ poly_verts.reserve(num_loops);
+ loop_counts.reserve(num_poly);
+
+ /* NOTE: data needs to be written in the reverse order. */
+ for (int i = 0; i < num_poly; ++i) {
+ MPoly &poly = mpoly[i];
+ loop_counts.push_back(poly.totloop);
+
+ smooth_normal |= ((poly.flag & ME_SMOOTH) != 0);
+
+ MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1);
+
+ for (int j = 0; j < poly.totloop; ++j, --loop) {
+ poly_verts.push_back(loop->v);
+ }
+ }
+}
+
+static void get_material_indices(DerivedMesh *dm, std::vector<int32_t> &indices)
+{
+ indices.clear();
+ indices.reserve(dm->getNumTessFaces(dm));
+
+ MPoly *mpolys = dm->getPolyArray(dm);
+
+ for (int i = 1, e = dm->getNumPolys(dm); i < e; ++i) {
+ MPoly *mpoly = &mpolys[i];
+ indices.push_back(mpoly->mat_nr);
+ }
+}
+
+static void get_creases(DerivedMesh *dm,
+ std::vector<int32_t> &indices,
+ std::vector<int32_t> &lengths,
+ std::vector<float> &sharpnesses)
+{
+ const float factor = 1.0f / 255.0f;
+
+ indices.clear();
+ lengths.clear();
+ sharpnesses.clear();
+
+ MEdge *edge = dm->getEdgeArray(dm);
+
+ for (int i = 0, e = dm->getNumEdges(dm); i < e; ++i) {
+ const float sharpness = static_cast<float>(edge[i].crease) * factor;
+
+ if (sharpness != 0.0f) {
+ indices.push_back(edge[i].v1);
+ indices.push_back(edge[i].v2);
+ sharpnesses.push_back(sharpness);
+ }
+ }
+
+ lengths.resize(sharpnesses.size(), 2);
+}
+
+static void get_vertex_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
+{
+ normals.clear();
+ normals.resize(dm->getNumVerts(dm));
+
+ MVert *verts = dm->getVertArray(dm);
+ float no[3];
+
+ for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
+ normal_short_to_float_v3(no, verts[i].no);
+ copy_zup_yup(normals[i].getValue(), no);
+ }
+}
+
+static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
+{
+ MPoly *mpoly = dm->getPolyArray(dm);
+ MPoly *mp = mpoly;
+
+ MLoop *mloop = dm->getLoopArray(dm);
+ MLoop *ml = mloop;
+
+ MVert *verts = dm->getVertArray(dm);
+
+ const float (*lnors)[3] = static_cast<float(*)[3]>(dm->getLoopDataArray(dm, CD_NORMAL));
+
+ normals.clear();
+ normals.resize(dm->getNumLoops(dm));
+
+ unsigned loop_index = 0;
+
+ /* NOTE: data needs to be written in the reverse order. */
+
+ if (lnors) {
+ for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i, ++mp) {
+ ml = mloop + mp->loopstart + (mp->totloop - 1);
+
+ for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
+ const int index = ml->v;
+ copy_zup_yup(normals[loop_index].getValue(), lnors[index]);
+ }
+ }
+ }
+ else {
+ float no[3];
+
+ for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i, ++mp) {
+ ml = mloop + mp->loopstart + (mp->totloop - 1);
+
+ /* Flat shaded, use common normal for all verts. */
+ if ((mp->flag & ME_SMOOTH) == 0) {
+ BKE_mesh_calc_poly_normal(mp, ml - (mp->totloop - 1), verts, no);
+
+ for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
+ copy_zup_yup(normals[loop_index].getValue(), no);
+ }
+ }
+ else {
+ /* Smooth shaded, use individual vert normals. */
+ for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
+ normal_short_to_float_v3(no, verts[ml->v].no);
+ copy_zup_yup(normals[loop_index].getValue(), no);
+ }
+ }
+ }
+ }
+}
+
+/* *************** Modifiers *************** */
+
+/* check if the mesh is a subsurf, ignoring disabled modifiers and
+ * displace if it's after subsurf. */
+static ModifierData *get_subsurf_modifier(Scene *scene, Object *ob)
+{
+ ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last);
+
+ for (; md; md = md->prev) {
+ if (!modifier_isEnabled(scene, md, eModifierMode_Render)) {
+ continue;
+ }
+
+ if (md->type == eModifierType_Subsurf) {
+ SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData*>(md);
+
+ if (smd->subdivType == ME_CC_SUBSURF) {
+ return md;
+ }
+ }
+
+ /* mesh is not a subsurf. break */
+ if ((md->type != eModifierType_Displace) && (md->type != eModifierType_ParticleSystem)) {
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob)
+{
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim);
+
+ if (md && (modifier_isEnabled(scene, md, eModifierMode_Render))) {
+ FluidsimModifierData *fsmd = reinterpret_cast<FluidsimModifierData *>(md);
+
+ if (fsmd->fss && fsmd->fss->type == OB_FLUIDSIM_DOMAIN) {
+ return md;
+ }
+ }
+
+ return NULL;
+}
+
+/* ************************************************************************** */
+
+AbcMeshWriter::AbcMeshWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings)
+ : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+{
+ m_is_animated = isAnimated();
+ m_subsurf_mod = NULL;
+ m_has_per_face_materials = false;
+ m_is_subd = false;
+
+ /* If the object is static, use the default static time sampling. */
+ if (!m_is_animated) {
+ time_sampling = 0;
+ }
+
+ if (!m_settings.apply_subdiv) {
+ m_subsurf_mod = get_subsurf_modifier(m_scene, m_object);
+ m_is_subd = (m_subsurf_mod != NULL);
+ }
+
+ m_is_liquid = (get_liquid_sim_modifier(m_scene, m_object) != NULL);
+
+ while (parent->alembicXform().getChildHeader(m_name)) {
+ m_name.append("_");
+ }
+
+ if (m_settings.use_subdiv_schema && m_is_subd) {
+ OSubD subd(parent->alembicXform(), m_name, m_time_sampling);
+ m_subdiv_schema = subd.getSchema();
+ }
+ else {
+ OPolyMesh mesh(parent->alembicXform(), m_name, m_time_sampling);
+ m_mesh_schema = mesh.getSchema();
+
+ OCompoundProperty typeContainer = m_mesh_schema.getUserProperties();
+ OBoolProperty type(typeContainer, "meshtype");
+ type.set(m_is_subd);
+ }
+}
+
+AbcMeshWriter::~AbcMeshWriter()
+{
+ if (m_subsurf_mod) {
+ m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary;
+ }
+}
+
+bool AbcMeshWriter::isAnimated() const
+{
+ /* Check if object has shape keys. */
+ Mesh *me = static_cast<Mesh *>(m_object->data);
+
+ if (me->key) {
+ return true;
+ }
+
+ /* Test modifiers. */
+ ModifierData *md = static_cast<ModifierData *>(m_object->modifiers.first);
+
+ while (md) {
+ if (md->type != eModifierType_Subsurf) {
+ return true;
+ }
+
+ md = md->next;
+ }
+
+ return false;
+}
+
+void AbcMeshWriter::do_write()
+{
+ /* We have already stored a sample for this object. */
+ if (!m_first_frame && !m_is_animated)
+ return;
+
+ DerivedMesh *dm = getFinalMesh();
+
+ try {
+ if (m_settings.use_subdiv_schema && m_subdiv_schema.valid()) {
+ writeSubD(dm);
+ }
+ else {
+ writeMesh(dm);
+ }
+
+ freeMesh(dm);
+ }
+ catch (...) {
+ freeMesh(dm);
+ throw;
+ }
+}
+
+void AbcMeshWriter::writeMesh(DerivedMesh *dm)
+{
+ std::vector<Imath::V3f> points, normals;
+ std::vector<int32_t> poly_verts, loop_counts;
+
+ bool smooth_normal = false;
+
+ get_vertices(dm, points);
+ get_topology(dm, poly_verts, loop_counts, smooth_normal);
+
+ if (m_first_frame) {
+ writeCommonData(dm, m_mesh_schema);
+ }
+
+ m_mesh_sample = OPolyMeshSchema::Sample(V3fArraySample(points),
+ Int32ArraySample(poly_verts),
+ Int32ArraySample(loop_counts));
+
+ UVSample sample;
+ if (m_settings.export_uvs) {
+ const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
+
+ if (!sample.indices.empty() && !sample.uvs.empty()) {
+ OV2fGeomParam::Sample uv_sample;
+ uv_sample.setVals(V2fArraySample(sample.uvs));
+ uv_sample.setIndices(UInt32ArraySample(sample.indices));
+ uv_sample.setScope(kFacevaryingScope);
+
+ m_mesh_schema.setUVSourceName(name);
+ m_mesh_sample.setUVs(uv_sample);
+ }
+
+ write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPUV);
+ }
+
+ if (m_settings.export_normals) {
+ if (smooth_normal) {
+ get_loop_normals(dm, normals);
+ }
+ else {
+ get_vertex_normals(dm, normals);
+ }
+
+ ON3fGeomParam::Sample normals_sample;
+ if (!normals.empty()) {
+ normals_sample.setScope((smooth_normal) ? kFacevaryingScope : kVertexScope);
+ normals_sample.setVals(V3fArraySample(normals));
+ }
+
+ m_mesh_sample.setNormals(normals_sample);
+ }
+
+ if (m_is_liquid) {
+ std::vector<Imath::V3f> velocities;
+ getVelocities(dm, velocities);
+
+ m_mesh_sample.setVelocities(V3fArraySample(velocities));
+ }
+
+ m_mesh_sample.setSelfBounds(bounds());
+
+ m_mesh_schema.set(m_mesh_sample);
+
+ writeArbGeoParams(dm);
+}
+
+void AbcMeshWriter::writeSubD(DerivedMesh *dm)
+{
+ std::vector<float> crease_sharpness;
+ std::vector<Imath::V3f> points;
+ std::vector<int32_t> poly_verts, loop_counts;
+ std::vector<int32_t> crease_indices, crease_lengths;
+
+ bool smooth_normal = false;
+
+ get_vertices(dm, points);
+ get_topology(dm, poly_verts, loop_counts, smooth_normal);
+ get_creases(dm, crease_indices, crease_lengths, crease_sharpness);
+
+ if (m_first_frame) {
+ /* create materials' face_sets */
+ writeCommonData(dm, m_subdiv_schema);
+ }
+
+ m_subdiv_sample = OSubDSchema::Sample(V3fArraySample(points),
+ Int32ArraySample(poly_verts),
+ Int32ArraySample(loop_counts));
+
+ UVSample sample;
+ if (m_settings.export_uvs) {
+ const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
+
+ if (!sample.indices.empty() && !sample.uvs.empty()) {
+ OV2fGeomParam::Sample uv_sample;
+ uv_sample.setVals(V2fArraySample(sample.uvs));
+ uv_sample.setIndices(UInt32ArraySample(sample.indices));
+ uv_sample.setScope(kFacevaryingScope);
+
+ m_subdiv_schema.setUVSourceName(name);
+ m_subdiv_sample.setUVs(uv_sample);
+ }
+
+ write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPUV);
+ }
+
+ if (!crease_indices.empty()) {
+ m_subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices));
+ m_subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths));
+ m_subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness));
+ }
+
+ m_subdiv_sample.setSelfBounds(bounds());
+ m_subdiv_schema.set(m_subdiv_sample);
+
+ writeArbGeoParams(dm);
+}
+
+template <typename Schema>
+void AbcMeshWriter::writeCommonData(DerivedMesh *dm, Schema &schema)
+{
+ std::map< std::string, std::vector<int32_t> > geo_groups;
+ getGeoGroups(dm, geo_groups);
+
+ std::map< std::string, std::vector<int32_t> >::iterator it;
+ for (it = geo_groups.begin(); it != geo_groups.end(); ++it) {
+ OFaceSet face_set = schema.createFaceSet(it->first);
+ OFaceSetSchema::Sample samp;
+ samp.setFaces(Int32ArraySample(it->second));
+ face_set.getSchema().set(samp);
+ }
+}
+
+DerivedMesh *AbcMeshWriter::getFinalMesh()
+{
+ /* We don't want subdivided mesh data */
+ if (m_subsurf_mod) {
+ m_subsurf_mod->mode |= eModifierMode_DisableTemporary;
+ }
+
+ DerivedMesh *dm = mesh_create_derived_render(m_scene, m_object, CD_MASK_MESH);
+
+ if (m_subsurf_mod) {
+ m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary;
+ }
+
+ m_custom_data_config.pack_uvs = m_settings.pack_uv;
+ m_custom_data_config.mpoly = dm->getPolyArray(dm);
+ m_custom_data_config.mloop = dm->getLoopArray(dm);
+ m_custom_data_config.totpoly = dm->getNumPolys(dm);
+ m_custom_data_config.totloop = dm->getNumLoops(dm);
+ m_custom_data_config.totvert = dm->getNumVerts(dm);
+
+ return dm;
+}
+
+void AbcMeshWriter::freeMesh(DerivedMesh *dm)
+{
+ dm->release(dm);
+}
+
+void AbcMeshWriter::writeArbGeoParams(DerivedMesh *dm)
+{
+ if (m_is_liquid) {
+ /* We don't need anything more for liquid meshes. */
+ return;
+ }
+
+ if (m_settings.export_vcols) {
+ if (m_subdiv_schema.valid()) {
+ write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL);
+ }
+ else {
+ write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL);
+ }
+ }
+
+ if (m_first_frame && m_has_per_face_materials) {
+ std::vector<int32_t> material_indices;
+
+ if (m_settings.export_face_sets) {
+ get_material_indices(dm, material_indices);
+
+ OFaceSetSchema::Sample samp;
+ samp.setFaces(Int32ArraySample(material_indices));
+ m_face_set.getSchema().set(samp);
+ }
+ }
+}
+
+void AbcMeshWriter::getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels)
+{
+ const int totverts = dm->getNumVerts(dm);
+
+ vels.clear();
+ vels.resize(totverts);
+
+ ModifierData *md = get_liquid_sim_modifier(m_scene, m_object);
+ FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(md);
+ FluidsimSettings *fss = fmd->fss;
+
+ if (fss->meshVelocities) {
+ float *mesh_vels = reinterpret_cast<float *>(fss->meshVelocities);
+
+ for (int i = 0; i < totverts; ++i) {
+ copy_zup_yup(vels[i].getValue(), mesh_vels);
+ mesh_vels += 3;
+ }
+ }
+ else {
+ std::fill(vels.begin(), vels.end(), Imath::V3f(0.0f));
+ }
+}
+
+void AbcMeshWriter::getGeoGroups(
+ DerivedMesh *dm,
+ std::map<std::string, std::vector<int32_t> > &geo_groups)
+{
+ const int num_poly = dm->getNumPolys(dm);
+ MPoly *polygons = dm->getPolyArray(dm);
+
+ for (int i = 0; i < num_poly; ++i) {
+ MPoly &current_poly = polygons[i];
+ short mnr = current_poly.mat_nr;
+
+ Material *mat = give_current_material(m_object, mnr + 1);
+
+ if (!mat) {
+ continue;
+ }
+
+ std::string name = get_id_name(&mat->id);
+
+ if (geo_groups.find(name) == geo_groups.end()) {
+ std::vector<int32_t> faceArray;
+ geo_groups[name] = faceArray;
+ }
+
+ geo_groups[name].push_back(i);
+ }
+
+ if (geo_groups.size() == 0) {
+ Material *mat = give_current_material(m_object, 1);
+
+ std::string name = (mat) ? get_id_name(&mat->id) : "default";
+
+ std::vector<int32_t> faceArray;
+
+ for (int i = 0, e = dm->getNumTessFaces(dm); i < e; ++i) {
+ faceArray.push_back(i);
+ }
+
+ geo_groups[name] = faceArray;
+ }
+}
+
+/* ************************************************************************** */
+
+/* Some helpers for mesh generation */
+namespace utils {
+
+void mesh_add_verts(Mesh *mesh, size_t len)
+{
+ if (len == 0) {
+ return;
+ }
+
+ const int totvert = mesh->totvert + len;
+ CustomData vdata;
+ CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
+ CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert);
+
+ if (!CustomData_has_layer(&vdata, CD_MVERT)) {
+ CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
+ }
+
+ CustomData_free(&mesh->vdata, mesh->totvert);
+ mesh->vdata = vdata;
+ BKE_mesh_update_customdata_pointers(mesh, false);
+
+ mesh->totvert = totvert;
+}
+
+static void mesh_add_mloops(Mesh *mesh, size_t len)
+{
+ if (len == 0) {
+ return;
+ }
+
+ /* new face count */
+ const int totloops = mesh->totloop + len;
+
+ CustomData ldata;
+ CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloops);
+ CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop);
+
+ if (!CustomData_has_layer(&ldata, CD_MLOOP)) {
+ CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloops);
+ }
+
+ CustomData_free(&mesh->ldata, mesh->totloop);
+ mesh->ldata = ldata;
+ BKE_mesh_update_customdata_pointers(mesh, false);
+
+ mesh->totloop = totloops;
+}
+
+static void mesh_add_mpolygons(Mesh *mesh, size_t len)
+{
+ if (len == 0) {
+ return;
+ }
+
+ const int totpolys = mesh->totpoly + len;
+
+ CustomData pdata;
+ CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpolys);
+ CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly);
+
+ if (!CustomData_has_layer(&pdata, CD_MPOLY)) {
+ CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpolys);
+ }
+
+ CustomData_free(&mesh->pdata, mesh->totpoly);
+ mesh->pdata = pdata;
+ BKE_mesh_update_customdata_pointers(mesh, false);
+
+ mesh->totpoly = totpolys;
+}
+
+static void build_mat_map(const Main *bmain, std::map<std::string, Material *> &mat_map)
+{
+ Material *material = static_cast<Material *>(bmain->mat.first);
+
+ for (; material; material = static_cast<Material *>(material->id.next)) {
+ mat_map[material->id.name + 2] = material;
+ }
+}
+
+static void assign_materials(Main *bmain, Object *ob, const std::map<std::string, int> &mat_index_map)
+{
+ bool can_assign = true;
+ std::map<std::string, int>::const_iterator it = mat_index_map.begin();
+
+ int matcount = 0;
+ for (; it != mat_index_map.end(); ++it, ++matcount) {
+ if (!BKE_object_material_slot_add(ob)) {
+ can_assign = false;
+ break;
+ }
+ }
+
+ /* TODO(kevin): use global map? */
+ std::map<std::string, Material *> mat_map;
+ build_mat_map(bmain, mat_map);
+
+ std::map<std::string, Material *>::iterator mat_iter;
+
+ if (can_assign) {
+ it = mat_index_map.begin();
+
+ for (; it != mat_index_map.end(); ++it) {
+ std::string mat_name = it->first;
+ mat_iter = mat_map.find(mat_name.c_str());
+
+ Material *assigned_name;
+
+ if (mat_iter == mat_map.end()) {
+ assigned_name = BKE_material_add(bmain, mat_name.c_str());
+ mat_map[mat_name] = assigned_name;
+ }
+ else {
+ assigned_name = mat_iter->second;
+ }
+
+ assign_material(ob, assigned_name, it->second, BKE_MAT_ASSIGN_OBJECT);
+ }
+ }
+}
+
+} /* namespace utils */
+
+/* ************************************************************************** */
+
+using Alembic::AbcGeom::UInt32ArraySamplePtr;
+using Alembic::AbcGeom::V2fArraySamplePtr;
+
+struct AbcMeshData {
+ Int32ArraySamplePtr face_indices;
+ Int32ArraySamplePtr face_counts;
+
+ P3fArraySamplePtr positions;
+
+ N3fArraySamplePtr vertex_normals;
+ N3fArraySamplePtr face_normals;
+
+ V2fArraySamplePtr uvs;
+ UInt32ArraySamplePtr uvs_indices;
+};
+
+static void *add_customdata_cb(void *user_data, const char *name, int data_type)
+{
+ Mesh *mesh = static_cast<Mesh *>(user_data);
+ CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
+ void *cd_ptr = NULL;
+
+ int index = -1;
+ if (cd_data_type == CD_MLOOPUV) {
+ index = ED_mesh_uv_texture_add(mesh, name, true);
+ cd_ptr = CustomData_get_layer(&mesh->ldata, cd_data_type);
+ }
+ else if (cd_data_type == CD_MLOOPCOL) {
+ index = ED_mesh_color_add(mesh, name, true);
+ cd_ptr = CustomData_get_layer(&mesh->ldata, cd_data_type);
+ }
+
+ if (index == -1) {
+ return NULL;
+ }
+
+ return cd_ptr;
+}
+
+CDStreamConfig create_config(Mesh *mesh)
+{
+ CDStreamConfig config;
+
+ config.mvert = mesh->mvert;
+ config.mpoly = mesh->mpoly;
+ config.mloop = mesh->mloop;
+ config.totpoly = mesh->totpoly;
+ config.totloop = mesh->totloop;
+ config.user_data = mesh;
+ config.loopdata = &mesh->ldata;
+ config.add_customdata_cb = add_customdata_cb;
+
+ return config;
+}
+
+static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data)
+{
+ MVert *mverts = config.mvert;
+ const P3fArraySamplePtr &positions = mesh_data.positions;
+ const N3fArraySamplePtr &normals = mesh_data.vertex_normals;
+
+ read_mverts(mverts, positions, normals);
+}
+
+void read_mverts(MVert *mverts, const P3fArraySamplePtr &positions, const N3fArraySamplePtr &normals)
+{
+ for (int i = 0; i < positions->size(); ++i) {
+ MVert &mvert = mverts[i];
+ Imath::V3f pos_in = (*positions)[i];
+
+ copy_yup_zup(mvert.co, pos_in.getValue());
+
+ mvert.bweight = 0;
+
+ if (normals) {
+ Imath::V3f nor_in = (*normals)[i];
+
+ short no[3];
+ normal_float_to_short_v3(no, nor_in.getValue());
+
+ copy_yup_zup(mvert.no, no);
+ }
+ }
+}
+
+static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
+{
+ MPoly *mpolys = config.mpoly;
+ MLoop *mloops = config.mloop;
+ MLoopUV *mloopuvs = config.mloopuv;
+
+ const Int32ArraySamplePtr &face_indices = mesh_data.face_indices;
+ const Int32ArraySamplePtr &face_counts = mesh_data.face_counts;
+ const V2fArraySamplePtr &uvs = mesh_data.uvs;
+ const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices;
+ const N3fArraySamplePtr &normals = mesh_data.face_normals;
+
+ const bool do_uvs = (mloopuvs && uvs && uvs_indices) && (uvs_indices->size() == face_indices->size());
+ unsigned int loop_index = 0;
+ unsigned int rev_loop_index = 0;
+ unsigned int uv_index = 0;
+
+ for (int i = 0; i < face_counts->size(); ++i) {
+ const int face_size = (*face_counts)[i];
+
+ MPoly &poly = mpolys[i];
+ poly.loopstart = loop_index;
+ poly.totloop = face_size;
+
+ if (normals != NULL) {
+ poly.flag |= ME_SMOOTH;
+ }
+
+ /* NOTE: Alembic data is stored in the reverse order. */
+ rev_loop_index = loop_index + (face_size - 1);
+
+ for (int f = 0; f < face_size; ++f, ++loop_index, --rev_loop_index) {
+ MLoop &loop = mloops[rev_loop_index];
+ loop.v = (*face_indices)[loop_index];
+
+ if (do_uvs) {
+ MLoopUV &loopuv = mloopuvs[rev_loop_index];
+
+ uv_index = (*uvs_indices)[loop_index];
+ loopuv.uv[0] = (*uvs)[uv_index][0];
+ loopuv.uv[1] = (*uvs)[uv_index][1];
+ }
+ }
+ }
+}
+
+ABC_INLINE void read_uvs_params(CDStreamConfig &config,
+ AbcMeshData &abc_data,
+ const IV2fGeomParam &uv,
+ const ISampleSelector &selector)
+{
+ if (!uv.valid()) {
+ return;
+ }
+
+ IV2fGeomParam::Sample uvsamp;
+ uv.getIndexed(uvsamp, selector);
+
+ abc_data.uvs = uvsamp.getVals();
+ abc_data.uvs_indices = uvsamp.getIndices();
+
+ if (abc_data.uvs_indices->size() == config.totloop) {
+ std::string name = Alembic::Abc::GetSourceName(uv.getMetaData());
+
+ /* According to the convention, primary UVs should have had their name
+ * set using Alembic::Abc::SetSourceName, but you can't expect everyone
+ * to follow it! :) */
+ if (name.empty()) {
+ name = uv.getName();
+ }
+
+ void *cd_ptr = config.add_customdata_cb(config.user_data, name.c_str(), CD_MLOOPUV);
+ config.mloopuv = static_cast<MLoopUV *>(cd_ptr);
+ }
+}
+
+/* TODO(kevin): normals from Alembic files are not read in anymore, this is due
+ * to the fact that there are many issues that are not so easy to solve, mainly
+ * regarding the way normals are handled in Blender (MPoly.flag vs loop normals).
+ */
+ABC_INLINE void read_normals_params(AbcMeshData &abc_data,
+ const IN3fGeomParam &normals,
+ const ISampleSelector &selector)
+{
+ if (!normals.valid()) {
+ return;
+ }
+
+ IN3fGeomParam::Sample normsamp = normals.getExpandedValue(selector);
+
+ if (normals.getScope() == kFacevaryingScope) {
+ abc_data.face_normals = normsamp.getVals();
+ }
+ else if ((normals.getScope() == kVertexScope) || (normals.getScope() == kVaryingScope)) {
+ abc_data.vertex_normals = N3fArraySamplePtr();
+ }
+}
+
+/* ************************************************************************** */
+
+AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ m_settings->read_flag |= MOD_MESHSEQ_READ_ALL;
+
+ IPolyMesh ipoly_mesh(m_iobject, kWrapExisting);
+ m_schema = ipoly_mesh.getSchema();
+ get_min_max_time(m_schema, m_min_time, m_max_time);
+}
+
+bool AbcMeshReader::valid() const
+{
+ return m_schema.valid();
+}
+
+void AbcMeshReader::readObjectData(Main *bmain, float time)
+{
+ Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
+
+ m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
+ m_object->data = mesh;
+
+ const ISampleSelector sample_sel(time);
+ const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+ const Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
+ const Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
+
+ utils::mesh_add_verts(mesh, positions->size());
+ utils::mesh_add_mpolygons(mesh, face_counts->size());
+ utils::mesh_add_mloops(mesh, face_indices->size());
+
+ m_mesh_data = create_config(mesh);
+
+ bool has_smooth_normals = false;
+ read_mesh_sample(m_settings, m_schema, sample_sel, m_mesh_data, has_smooth_normals);
+
+ BKE_mesh_calc_normals(mesh);
+ BKE_mesh_calc_edges(mesh, false, false);
+
+ if (m_settings->validate_meshes) {
+ BKE_mesh_validate(mesh, false, false);
+ }
+
+ readFaceSetsSample(bmain, mesh, 0, sample_sel);
+
+ if (has_animations(m_schema, m_settings)) {
+ addCacheModifier();
+ }
+}
+
+void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
+ const ISampleSelector &sample_sel)
+{
+ std::vector<std::string> face_sets;
+ m_schema.getFaceSetNames(face_sets);
+
+ if (face_sets.empty()) {
+ return;
+ }
+
+ std::map<std::string, int> mat_map;
+ int current_mat = 0;
+
+ for (int i = 0; i < face_sets.size(); ++i) {
+ const std::string &grp_name = face_sets[i];
+
+ if (mat_map.find(grp_name) == mat_map.end()) {
+ mat_map[grp_name] = 1 + current_mat++;
+ }
+
+ const int assigned_mat = mat_map[grp_name];
+
+ const IFaceSet faceset = m_schema.getFaceSet(grp_name);
+
+ if (!faceset.valid()) {
+ continue;
+ }
+
+ const IFaceSetSchema face_schem = faceset.getSchema();
+ const IFaceSetSchema::Sample face_sample = face_schem.getValue(sample_sel);
+ const Int32ArraySamplePtr group_faces = face_sample.getFaces();
+ const size_t num_group_faces = group_faces->size();
+
+ for (size_t l = 0; l < num_group_faces; l++) {
+ size_t pos = (*group_faces)[l] + poly_start;
+
+ if (pos >= mesh->totpoly) {
+ std::cerr << "Faceset overflow on " << faceset.getName() << '\n';
+ break;
+ }
+
+ MPoly &poly = mesh->mpoly[pos];
+ poly.mat_nr = assigned_mat - 1;
+ }
+ }
+
+ utils::assign_materials(bmain, m_object, mat_map);
+}
+
+void read_mesh_sample(ImportSettings *settings,
+ const IPolyMeshSchema &schema,
+ const ISampleSelector &selector,
+ CDStreamConfig &config,
+ bool &do_normals)
+{
+ const IPolyMeshSchema::Sample sample = schema.getValue(selector);
+
+ AbcMeshData abc_mesh_data;
+ abc_mesh_data.face_counts = sample.getFaceCounts();
+ abc_mesh_data.face_indices = sample.getFaceIndices();
+ abc_mesh_data.positions = sample.getPositions();
+
+ read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector);
+
+ do_normals = (abc_mesh_data.face_normals != NULL);
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
+ read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
+ read_mverts(config, abc_mesh_data);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
+ read_mpolys(config, abc_mesh_data);
+ }
+
+ if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
+ read_custom_data(schema.getArbGeomParams(), config, selector);
+ }
+
+ /* TODO: face sets */
+}
+
+/* ************************************************************************** */
+
+ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
+{
+ for (int i = 0, e = totedge; i < e; ++i) {
+ MEdge &edge = edges[i];
+
+ if (edge.v1 == v1 && edge.v2 == v2) {
+ return &edge;
+ }
+ }
+
+ return NULL;
+}
+
+AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ m_settings->read_flag |= MOD_MESHSEQ_READ_ALL;
+
+ ISubD isubd_mesh(m_iobject, kWrapExisting);
+ m_schema = isubd_mesh.getSchema();
+ get_min_max_time(m_schema, m_min_time, m_max_time);
+}
+
+bool AbcSubDReader::valid() const
+{
+ return m_schema.valid();
+}
+
+void AbcSubDReader::readObjectData(Main *bmain, float time)
+{
+ Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
+
+ m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
+ m_object->data = mesh;
+
+ const ISampleSelector sample_sel(time);
+ const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+ const Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
+ const Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
+
+ utils::mesh_add_verts(mesh, positions->size());
+ utils::mesh_add_mpolygons(mesh, face_counts->size());
+ utils::mesh_add_mloops(mesh, face_indices->size());
+
+ m_mesh_data = create_config(mesh);
+
+ read_subd_sample(m_settings, m_schema, sample_sel, m_mesh_data);
+
+ Int32ArraySamplePtr indices = sample.getCreaseIndices();
+ Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses();
+
+ MEdge *edges = mesh->medge;
+
+ if (indices && sharpnesses) {
+ for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, ++s) {
+ MEdge *edge = find_edge(edges, mesh->totedge, (*indices)[i], (*indices)[i + 1]);
+
+ if (edge) {
+ edge->crease = FTOCHAR((*sharpnesses)[s]);
+ }
+ }
+
+ mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
+ }
+
+ BKE_mesh_calc_normals(mesh);
+ BKE_mesh_calc_edges(mesh, false, false);
+
+ if (m_settings->validate_meshes) {
+ BKE_mesh_validate(mesh, false, false);
+ }
+
+ if (has_animations(m_schema, m_settings)) {
+ addCacheModifier();
+ }
+}
+
+void read_subd_sample(ImportSettings *settings,
+ const ISubDSchema &schema,
+ const ISampleSelector &selector,
+ CDStreamConfig &config)
+{
+ const ISubDSchema::Sample sample = schema.getValue(selector);
+
+ AbcMeshData abc_mesh_data;
+ abc_mesh_data.face_counts = sample.getFaceCounts();
+ abc_mesh_data.face_indices = sample.getFaceIndices();
+ abc_mesh_data.vertex_normals = N3fArraySamplePtr();
+ abc_mesh_data.face_normals = N3fArraySamplePtr();
+ abc_mesh_data.positions = sample.getPositions();
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
+ read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
+ read_mverts(config, abc_mesh_data);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
+ read_mpolys(config, abc_mesh_data);
+ }
+
+ if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
+ read_custom_data(schema.getArbGeomParams(), config, selector);
+ }
+
+ /* TODO: face sets */
+}
diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h
new file mode 100644
index 00000000000..9dc222e5206
--- /dev/null
+++ b/source/blender/alembic/intern/abc_mesh.h
@@ -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.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_MESH_H__
+#define __ABC_MESH_H__
+
+#include "abc_customdata.h"
+#include "abc_object.h"
+
+struct DerivedMesh;
+struct Mesh;
+struct ModifierData;
+
+/* ************************************************************************** */
+
+class AbcMeshWriter : public AbcObjectWriter {
+ Alembic::AbcGeom::OPolyMeshSchema m_mesh_schema;
+ Alembic::AbcGeom::OPolyMeshSchema::Sample m_mesh_sample;
+
+ Alembic::AbcGeom::OSubDSchema m_subdiv_schema;
+ Alembic::AbcGeom::OSubDSchema::Sample m_subdiv_sample;
+
+ bool m_has_per_face_materials;
+ Alembic::AbcGeom::OFaceSet m_face_set;
+ Alembic::Abc::OArrayProperty m_mat_indices;
+
+ bool m_is_animated;
+ ModifierData *m_subsurf_mod;
+
+ CDStreamConfig m_custom_data_config;
+
+ bool m_is_liquid;
+ bool m_is_subd;
+
+public:
+ AbcMeshWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings);
+
+ ~AbcMeshWriter();
+
+private:
+ virtual void do_write();
+
+ bool isAnimated() const;
+
+ void writeMesh(DerivedMesh *dm);
+ void writeSubD(DerivedMesh *dm);
+
+ void getMeshInfo(DerivedMesh *dm, std::vector<float> &points,
+ std::vector<int32_t> &facePoints,
+ std::vector<int32_t> &faceCounts,
+ std::vector<int32_t> &creaseIndices,
+ std::vector<int32_t> &creaseLengths,
+ std::vector<float> &creaseSharpness);
+
+ DerivedMesh *getFinalMesh();
+ void freeMesh(DerivedMesh *dm);
+
+ void getMaterialIndices(DerivedMesh *dm, std::vector<int32_t> &indices);
+
+ void writeArbGeoParams(DerivedMesh *dm);
+ void getGeoGroups(DerivedMesh *dm, std::map<std::string, std::vector<int32_t> > &geoGroups);
+
+ /* fluid surfaces support */
+ void getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels);
+
+ template <typename Schema>
+ void writeCommonData(DerivedMesh *dm, Schema &schema);
+};
+
+/* ************************************************************************** */
+
+class AbcMeshReader : public AbcObjectReader {
+ Alembic::AbcGeom::IPolyMeshSchema m_schema;
+
+ CDStreamConfig m_mesh_data;
+
+public:
+ AbcMeshReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+
+private:
+ void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
+ const Alembic::AbcGeom::ISampleSelector &sample_sel);
+};
+
+void read_mesh_sample(ImportSettings *settings,
+ const Alembic::AbcGeom::IPolyMeshSchema &schema,
+ const Alembic::AbcGeom::ISampleSelector &selector,
+ CDStreamConfig &config,
+ bool &do_normals);
+
+/* ************************************************************************** */
+
+class AbcSubDReader : public AbcObjectReader {
+ Alembic::AbcGeom::ISubDSchema m_schema;
+
+ CDStreamConfig m_mesh_data;
+
+public:
+ AbcSubDReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+};
+
+void read_subd_sample(ImportSettings *settings,
+ const Alembic::AbcGeom::ISubDSchema &schema,
+ const Alembic::AbcGeom::ISampleSelector &selector,
+ CDStreamConfig &config);
+
+/* ************************************************************************** */
+
+namespace utils {
+
+void mesh_add_verts(struct Mesh *mesh, size_t len);
+
+}
+
+void read_mverts(MVert *mverts,
+ const Alembic::AbcGeom::P3fArraySamplePtr &positions,
+ const Alembic::AbcGeom::N3fArraySamplePtr &normals);
+
+CDStreamConfig create_config(Mesh *mesh);
+
+#endif /* __ABC_MESH_H__ */
diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc
new file mode 100644
index 00000000000..a3c18ad6301
--- /dev/null
+++ b/source/blender/alembic/intern/abc_nurbs.cc
@@ -0,0 +1,367 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_nurbs.h"
+
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_curve.h"
+#include "BKE_object.h"
+}
+
+using Alembic::AbcGeom::bool_t;
+using Alembic::AbcGeom::FloatArraySample;
+using Alembic::AbcGeom::FloatArraySamplePtr;
+using Alembic::AbcGeom::MetaData;
+using Alembic::AbcGeom::P3fArraySamplePtr;
+using Alembic::AbcGeom::kWrapExisting;
+
+using Alembic::AbcGeom::IBoolProperty;
+using Alembic::AbcGeom::ICompoundProperty;
+using Alembic::AbcGeom::INuPatch;
+using Alembic::AbcGeom::INuPatchSchema;
+using Alembic::AbcGeom::IObject;
+using Alembic::AbcGeom::ISampleSelector;
+
+using Alembic::AbcGeom::OBoolProperty;
+using Alembic::AbcGeom::OCompoundProperty;
+using Alembic::AbcGeom::ONuPatch;
+using Alembic::AbcGeom::ONuPatchSchema;
+
+/* ************************************************************************** */
+
+AbcNurbsWriter::AbcNurbsWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings)
+ : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+{
+ m_is_animated = isAnimated();
+
+ /* if the object is static, use the default static time sampling */
+ if (!m_is_animated) {
+ m_time_sampling = 0;
+ }
+
+ Curve *curve = static_cast<Curve *>(m_object->data);
+ size_t numNurbs = BLI_listbase_count(&curve->nurb);
+
+ for (size_t i = 0; i < numNurbs; ++i) {
+ std::stringstream str;
+ str << m_name << '_' << i;
+
+ while (parent->alembicXform().getChildHeader(str.str())) {
+ str << "_";
+ }
+
+ ONuPatch nurbs(parent->alembicXform(), str.str().c_str(), m_time_sampling);
+ m_nurbs_schema.push_back(nurbs.getSchema());
+ }
+}
+
+bool AbcNurbsWriter::isAnimated() const
+{
+ /* check if object has shape keys */
+ Curve *cu = static_cast<Curve *>(m_object->data);
+ return (cu->key != NULL);
+}
+
+static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_knots)
+{
+ if (num_knots <= 1) {
+ return;
+ }
+
+ /* Add an extra knot at the beggining and end of the array since most apps
+ * require/expect them. */
+ knots.reserve(num_knots + 2);
+
+ knots.push_back(0.0f);
+
+ for (int i = 0; i < num_knots; ++i) {
+ knots.push_back(nu_knots[i]);
+ }
+
+ knots[0] = 2.0f * knots[1] - knots[2];
+ knots.push_back(2.0f * knots[num_knots] - knots[num_knots - 1]);
+}
+
+void AbcNurbsWriter::do_write()
+{
+ /* we have already stored a sample for this object. */
+ if (!m_first_frame && !m_is_animated) {
+ return;
+ }
+
+ if (!ELEM(m_object->type, OB_SURF, OB_CURVE)) {
+ return;
+ }
+
+ Curve *curve = static_cast<Curve *>(m_object->data);
+ ListBase *nulb;
+
+ if (m_object->curve_cache->deformed_nurbs.first != NULL) {
+ nulb = &m_object->curve_cache->deformed_nurbs;
+ }
+ else {
+ nulb = BKE_curve_nurbs_get(curve);
+ }
+
+ size_t count = 0;
+ for (Nurb *nu = static_cast<Nurb *>(nulb->first); nu; nu = nu->next, ++count) {
+ std::vector<float> knotsU;
+ get_knots(knotsU, KNOTSU(nu), nu->knotsu);
+
+ std::vector<float> knotsV;
+ get_knots(knotsV, KNOTSV(nu), nu->knotsv);
+
+ const int size = nu->pntsu * nu->pntsv;
+ std::vector<Imath::V3f> positions(size);
+ std::vector<float> weights(size);
+
+ const BPoint *bp = nu->bp;
+
+ for (int i = 0; i < size; ++i, ++bp) {
+ copy_zup_yup(positions[i].getValue(), bp->vec);
+ weights[i] = bp->vec[3];
+ }
+
+ ONuPatchSchema::Sample sample;
+ sample.setUOrder(nu->orderu + 1);
+ sample.setVOrder(nu->orderv + 1);
+ sample.setPositions(positions);
+ sample.setPositionWeights(weights);
+ sample.setUKnot(FloatArraySample(knotsU));
+ sample.setVKnot(FloatArraySample(knotsV));
+ sample.setNu(nu->pntsu);
+ sample.setNv(nu->pntsv);
+
+ /* TODO(kevin): to accomodate other software we should duplicate control
+ * points to indicate that a NURBS is cyclic. */
+ OCompoundProperty user_props = m_nurbs_schema[count].getUserProperties();
+
+ if ((nu->flagu & CU_NURB_ENDPOINT) != 0) {
+ OBoolProperty prop(user_props, "endpoint_u");
+ prop.set(true);
+ }
+
+ if ((nu->flagv & CU_NURB_ENDPOINT) != 0) {
+ OBoolProperty prop(user_props, "endpoint_v");
+ prop.set(true);
+ }
+
+ if ((nu->flagu & CU_NURB_CYCLIC) != 0) {
+ OBoolProperty prop(user_props, "cyclic_u");
+ prop.set(true);
+ }
+
+ if ((nu->flagv & CU_NURB_CYCLIC) != 0) {
+ OBoolProperty prop(user_props, "cyclic_v");
+ prop.set(true);
+ }
+
+ m_nurbs_schema[count].set(sample);
+ }
+}
+
+/* ************************************************************************** */
+
+AbcNurbsReader::AbcNurbsReader(const IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ getNurbsPatches(m_iobject);
+ get_min_max_time(m_schemas[0].first, m_min_time, m_max_time);
+}
+
+bool AbcNurbsReader::valid() const
+{
+ if (m_schemas.empty()) {
+ return false;
+ }
+
+ std::vector< std::pair<INuPatchSchema, IObject> >::const_iterator it;
+ for (it = m_schemas.begin(); it != m_schemas.end(); ++it) {
+ const INuPatchSchema &schema = it->first;
+
+ if (!schema.valid()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots)
+{
+ if (!knots || knots->size() == 0) {
+ return false;
+ }
+
+ /* Skip first and last knots, as they are used for padding. */
+ const size_t num_knots = knots->size() - 2;
+ nu_knots = static_cast<float *>(MEM_callocN(num_knots * sizeof(float), "abc_setsplineknotsu"));
+
+ for (size_t i = 0; i < num_knots; ++i) {
+ nu_knots[i] = (*knots)[i + 1];
+ }
+
+ return true;
+}
+
+void AbcNurbsReader::readObjectData(Main *bmain, float time)
+{
+ Curve *cu = static_cast<Curve *>(BKE_curve_add(bmain, "abc_curve", OB_SURF));
+ cu->actvert = CU_ACT_NONE;
+
+ std::vector< std::pair<INuPatchSchema, IObject> >::iterator it;
+
+ for (it = m_schemas.begin(); it != m_schemas.end(); ++it) {
+ Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
+ nu->flag = CU_SMOOTH;
+ nu->type = CU_NURBS;
+ nu->resolu = cu->resolu;
+ nu->resolv = cu->resolv;
+
+ const ISampleSelector sample_sel(time);
+ const INuPatchSchema &schema = it->first;
+ const INuPatchSchema::Sample smp = schema.getValue(sample_sel);
+
+ nu->orderu = smp.getUOrder() - 1;
+ nu->orderv = smp.getVOrder() - 1;
+ nu->pntsu = smp.getNumU();
+ nu->pntsv = smp.getNumV();
+
+ /* Read positions and weights. */
+
+ const P3fArraySamplePtr positions = smp.getPositions();
+ const FloatArraySamplePtr weights = smp.getPositionWeights();
+
+ const size_t num_points = positions->size();
+
+ nu->bp = static_cast<BPoint *>(MEM_callocN(num_points * sizeof(BPoint), "abc_setsplinetype"));
+
+ BPoint *bp = nu->bp;
+ float posw_in = 1.0f;
+
+ for (int i = 0; i < num_points; ++i, ++bp) {
+ const Imath::V3f &pos_in = (*positions)[i];
+
+ if (weights) {
+ posw_in = (*weights)[i];
+ }
+
+ copy_yup_zup(bp->vec, pos_in.getValue());
+ bp->vec[3] = posw_in;
+ bp->f1 = SELECT;
+ bp->radius = 1.0f;
+ bp->weight = 1.0f;
+ }
+
+ /* Read knots. */
+
+ if (!set_knots(smp.getUKnot(), nu->knotsu)) {
+ BKE_nurb_knot_calc_u(nu);
+ }
+
+ if (!set_knots(smp.getVKnot(), nu->knotsv)) {
+ BKE_nurb_knot_calc_v(nu);
+ }
+
+ /* Read flags. */
+
+ ICompoundProperty user_props = schema.getUserProperties();
+
+ if (has_property(user_props, "enpoint_u")) {
+ nu->flagu |= CU_NURB_ENDPOINT;
+ }
+
+ if (has_property(user_props, "enpoint_v")) {
+ nu->flagv |= CU_NURB_ENDPOINT;
+ }
+
+ if (has_property(user_props, "cyclic_u")) {
+ nu->flagu |= CU_NURB_CYCLIC;
+ }
+
+ if (has_property(user_props, "cyclic_v")) {
+ nu->flagv |= CU_NURB_CYCLIC;
+ }
+
+ BLI_addtail(BKE_curve_nurbs_get(cu), nu);
+ }
+
+ BLI_strncpy(cu->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1);
+
+ m_object = BKE_object_add_only_object(bmain, OB_SURF, m_object_name.c_str());
+ m_object->data = cu;
+}
+
+void AbcNurbsReader::getNurbsPatches(const IObject &obj)
+{
+ if (!obj.valid()) {
+ return;
+ }
+
+ const int num_children = obj.getNumChildren();
+
+ if (num_children == 0) {
+ INuPatch abc_nurb(obj, kWrapExisting);
+ INuPatchSchema schem = abc_nurb.getSchema();
+ m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, obj));
+ return;
+ }
+
+ for (int i = 0; i < num_children; ++i) {
+ bool ok = true;
+ IObject child(obj, obj.getChildHeader(i).getName());
+
+ if (!m_name.empty() && child.valid() && !begins_with(child.getFullName(), m_name)) {
+ ok = false;
+ }
+
+ if (!child.valid()) {
+ continue;
+ }
+
+ const MetaData &md = child.getMetaData();
+
+ if (INuPatch::matches(md) && ok) {
+ INuPatch abc_nurb(child, kWrapExisting);
+ INuPatchSchema schem = abc_nurb.getSchema();
+ m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, child));
+ }
+
+ getNurbsPatches(child);
+ }
+}
diff --git a/source/blender/alembic/intern/abc_nurbs.h b/source/blender/alembic/intern/abc_nurbs.h
new file mode 100644
index 00000000000..1b2e7a8391f
--- /dev/null
+++ b/source/blender/alembic/intern/abc_nurbs.h
@@ -0,0 +1,63 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_NURBS_H__
+#define __ABC_NURBS_H__
+
+#include "abc_object.h"
+
+/* ************************************************************************** */
+
+class AbcNurbsWriter : public AbcObjectWriter {
+ std::vector<Alembic::AbcGeom::ONuPatchSchema> m_nurbs_schema;
+ bool m_is_animated;
+
+public:
+ AbcNurbsWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings);
+
+private:
+ virtual void do_write();
+
+ bool isAnimated() const;
+};
+
+/* ************************************************************************** */
+
+class AbcNurbsReader : public AbcObjectReader {
+ std::vector< std::pair<Alembic::AbcGeom::INuPatchSchema, Alembic::Abc::IObject> > m_schemas;
+
+public:
+ AbcNurbsReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+
+private:
+ void getNurbsPatches(const Alembic::Abc::IObject &obj);
+};
+
+#endif /* __ABC_NURBS_H__ */
diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc
new file mode 100644
index 00000000000..5b7b85f10ea
--- /dev/null
+++ b/source/blender/alembic/intern/abc_object.cc
@@ -0,0 +1,238 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_object.h"
+
+#include "abc_util.h"
+
+extern "C" {
+#include "DNA_cachefile_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX */
+
+#include "BKE_constraint.h"
+#include "BKE_depsgraph.h"
+#include "BKE_idprop.h"
+#include "BKE_library.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+}
+
+using Alembic::AbcGeom::IObject;
+using Alembic::AbcGeom::IXform;
+using Alembic::AbcGeom::IXformSchema;
+
+using Alembic::AbcGeom::OCompoundProperty;
+using Alembic::AbcGeom::ODoubleArrayProperty;
+using Alembic::AbcGeom::ODoubleProperty;
+using Alembic::AbcGeom::OFloatArrayProperty;
+using Alembic::AbcGeom::OFloatProperty;
+using Alembic::AbcGeom::OInt32ArrayProperty;
+using Alembic::AbcGeom::OInt32Property;
+using Alembic::AbcGeom::OStringArrayProperty;
+using Alembic::AbcGeom::OStringProperty;
+
+/* ************************************************************************** */
+
+AbcObjectWriter::AbcObjectWriter(Scene *scene,
+ Object *ob,
+ uint32_t time_sampling,
+ ExportSettings &settings,
+ AbcObjectWriter *parent)
+ : m_object(ob)
+ , m_settings(settings)
+ , m_scene(scene)
+ , m_time_sampling(time_sampling)
+ , m_first_frame(true)
+{
+ m_name = get_id_name(m_object) + "Shape";
+
+ if (parent) {
+ parent->addChild(this);
+ }
+}
+
+AbcObjectWriter::~AbcObjectWriter()
+{}
+
+void AbcObjectWriter::addChild(AbcObjectWriter *child)
+{
+ m_children.push_back(child);
+}
+
+Imath::Box3d AbcObjectWriter::bounds()
+{
+ BoundBox *bb = BKE_object_boundbox_get(this->m_object);
+
+ if (!bb) {
+ if (this->m_object->type != OB_CAMERA) {
+ std::cerr << "Boundbox is null!\n";
+ }
+
+ return Imath::Box3d();
+ }
+
+ /* Convert Z-up to Y-up. */
+ this->m_bounds.min.x = bb->vec[0][0];
+ this->m_bounds.min.y = bb->vec[0][2];
+ this->m_bounds.min.z = -bb->vec[0][1];
+
+ this->m_bounds.max.x = bb->vec[6][0];
+ this->m_bounds.max.y = bb->vec[6][2];
+ this->m_bounds.max.z = -bb->vec[6][1];
+
+ return this->m_bounds;
+}
+
+void AbcObjectWriter::write()
+{
+ do_write();
+ m_first_frame = false;
+}
+
+/* ************************************************************************** */
+
+AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings)
+ : m_name("")
+ , m_object_name("")
+ , m_data_name("")
+ , m_object(NULL)
+ , m_iobject(object)
+ , m_settings(&settings)
+ , m_min_time(std::numeric_limits<chrono_t>::max())
+ , m_max_time(std::numeric_limits<chrono_t>::min())
+{
+ m_name = object.getFullName();
+ std::vector<std::string> parts;
+ split(m_name, '/', parts);
+
+ if (parts.size() >= 2) {
+ m_object_name = parts[parts.size() - 2];
+ m_data_name = parts[parts.size() - 1];
+ }
+ else {
+ m_object_name = m_data_name = parts[parts.size() - 1];
+ }
+}
+
+AbcObjectReader::~AbcObjectReader()
+{}
+
+const IObject &AbcObjectReader::iobject() const
+{
+ return m_iobject;
+}
+
+Object *AbcObjectReader::object() const
+{
+ return m_object;
+}
+
+void AbcObjectReader::readObjectMatrix(const float time)
+{
+ IXform ixform;
+ bool has_alembic_parent = false;
+
+ /* Check that we have an empty object (locator, bone head/tail...). */
+ if (IXform::matches(m_iobject.getMetaData())) {
+ ixform = IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
+
+ /* See comment below. */
+ has_alembic_parent = m_iobject.getParent().getParent().valid();
+ }
+ /* Check that we have an object with actual data. */
+ else if (IXform::matches(m_iobject.getParent().getMetaData())) {
+ ixform = IXform(m_iobject.getParent(), Alembic::AbcGeom::kWrapExisting);
+
+ /* This is a bit hackish, but we need to make sure that extra
+ * transformations added to the matrix (rotation/scale) are only applied
+ * to root objects. The way objects and their hierarchy are created will
+ * need to be revisited at some point but for now this seems to do the
+ * trick.
+ *
+ * Explanation of the trick:
+ * The first getParent() will return this object's transformation matrix.
+ * The second getParent() will get the parent of the transform, but this
+ * might be the archive root ('/') which is valid, so we go passed it to
+ * make sure that there is no parent.
+ */
+ has_alembic_parent = m_iobject.getParent().getParent().getParent().valid();
+ }
+ /* Should not happen. */
+ else {
+ return;
+ }
+
+ const IXformSchema &schema(ixform.getSchema());
+
+ if (!schema.valid()) {
+ return;
+ }
+
+ Alembic::AbcGeom::ISampleSelector sample_sel(time);
+ Alembic::AbcGeom::XformSample xs;
+ schema.get(xs, sample_sel);
+
+ create_input_transform(sample_sel, ixform, m_object, m_object->obmat, m_settings->scale, has_alembic_parent);
+
+ invert_m4_m4(m_object->imat, m_object->obmat);
+
+ BKE_object_apply_mat4(m_object, m_object->obmat, false, false);
+
+ if (!schema.isConstant()) {
+ bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE);
+ bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data);
+ BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
+
+ data->cache_file = m_settings->cache_file;
+ id_us_plus(&data->cache_file->id);
+ }
+}
+
+void AbcObjectReader::addCacheModifier() const
+{
+ ModifierData *md = modifier_new(eModifierType_MeshSequenceCache);
+ BLI_addtail(&m_object->modifiers, md);
+
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
+
+ mcmd->cache_file = m_settings->cache_file;
+ id_us_plus(&mcmd->cache_file->id);
+
+ BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
+}
+
+chrono_t AbcObjectReader::minTime() const
+{
+ return m_min_time;
+}
+
+chrono_t AbcObjectReader::maxTime() const
+{
+ return m_max_time;
+}
diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h
new file mode 100644
index 00000000000..2e885f296b1
--- /dev/null
+++ b/source/blender/alembic/intern/abc_object.h
@@ -0,0 +1,169 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_OBJECT_H__
+#define __ABC_OBJECT_H__
+
+#include <Alembic/Abc/All.h>
+#include <Alembic/AbcGeom/All.h>
+
+#include "abc_exporter.h"
+
+extern "C" {
+#include "DNA_ID.h"
+}
+
+class AbcTransformWriter;
+
+struct Main;
+struct Object;
+
+/* ************************************************************************** */
+
+class AbcObjectWriter {
+protected:
+ Object *m_object;
+ ExportSettings &m_settings;
+
+ Scene *m_scene;
+ uint32_t m_time_sampling;
+
+ Imath::Box3d m_bounds;
+ std::vector<AbcObjectWriter *> m_children;
+
+ std::vector< std::pair<std::string, IDProperty *> > m_props;
+
+ bool m_first_frame;
+ std::string m_name;
+
+public:
+ AbcObjectWriter(Scene *scene,
+ Object *ob,
+ uint32_t time_sampling,
+ ExportSettings &settings,
+ AbcObjectWriter *parent = NULL);
+
+ virtual ~AbcObjectWriter();
+
+ void addChild(AbcObjectWriter *child);
+
+ virtual Imath::Box3d bounds();
+
+ void write();
+
+private:
+ virtual void do_write() = 0;
+};
+
+/* ************************************************************************** */
+
+class CacheFile;
+
+struct ImportSettings {
+ bool do_convert_mat;
+ float conversion_mat[4][4];
+
+ int from_up;
+ int from_forward;
+ float scale;
+ bool is_sequence;
+ bool set_frame_range;
+
+ /* Length and frame offset of file sequences. */
+ int sequence_len;
+ int offset;
+
+ /* From MeshSeqCacheModifierData.read_flag */
+ int read_flag;
+
+ bool validate_meshes;
+
+ CacheFile *cache_file;
+
+ ImportSettings()
+ : do_convert_mat(false)
+ , from_up(0)
+ , from_forward(0)
+ , scale(1.0f)
+ , is_sequence(false)
+ , set_frame_range(false)
+ , sequence_len(1)
+ , offset(0)
+ , read_flag(0)
+ , validate_meshes(false)
+ , cache_file(NULL)
+ {}
+};
+
+template <typename Schema>
+static bool has_animations(Schema &schema, ImportSettings *settings)
+{
+ if (settings->is_sequence) {
+ return true;
+ }
+
+ if (!schema.isConstant()) {
+ return true;
+ }
+
+ return false;
+}
+
+/* ************************************************************************** */
+
+using Alembic::AbcCoreAbstract::chrono_t;
+
+class AbcObjectReader {
+protected:
+ std::string m_name;
+ std::string m_object_name;
+ std::string m_data_name;
+ Object *m_object;
+ Alembic::Abc::IObject m_iobject;
+
+ ImportSettings *m_settings;
+
+ chrono_t m_min_time;
+ chrono_t m_max_time;
+
+public:
+ explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ virtual ~AbcObjectReader();
+
+ const Alembic::Abc::IObject &iobject() const;
+
+ Object *object() const;
+
+ virtual bool valid() const = 0;
+
+ virtual void readObjectData(Main *bmain, float time) = 0;
+
+ void readObjectMatrix(const float time);
+
+ void addCacheModifier() const;
+
+ chrono_t minTime() const;
+ chrono_t maxTime() const;
+};
+
+#endif /* __ABC_OBJECT_H__ */
diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc
new file mode 100644
index 00000000000..fa5b71ac094
--- /dev/null
+++ b/source/blender/alembic/intern/abc_points.cc
@@ -0,0 +1,198 @@
+/*
+ * ***** 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) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#include "abc_points.h"
+
+#include "abc_mesh.h"
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "DNA_mesh_types.h"
+
+#include "BKE_lattice.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_scene.h"
+
+#include "BLI_math.h"
+}
+
+using Alembic::AbcGeom::kVertexScope;
+using Alembic::AbcGeom::kWrapExisting;
+using Alembic::AbcGeom::P3fArraySamplePtr;
+using Alembic::AbcGeom::N3fArraySamplePtr;
+
+using Alembic::AbcGeom::ICompoundProperty;
+using Alembic::AbcGeom::IN3fArrayProperty;
+using Alembic::AbcGeom::IPoints;
+using Alembic::AbcGeom::IPointsSchema;
+using Alembic::AbcGeom::ISampleSelector;
+
+using Alembic::AbcGeom::OPoints;
+using Alembic::AbcGeom::OPointsSchema;
+
+/* ************************************************************************** */
+
+AbcPointsWriter::AbcPointsWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings,
+ ParticleSystem *psys)
+ : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+{
+ m_psys = psys;
+
+ OPoints points(parent->alembicXform(), m_name, m_time_sampling);
+ m_schema = points.getSchema();
+}
+
+void AbcPointsWriter::do_write()
+{
+ if (!m_psys) {
+ return;
+ }
+
+ std::vector<Imath::V3f> points;
+ std::vector<Imath::V3f> velocities;
+ std::vector<float> widths;
+ std::vector<uint64_t> ids;
+
+ ParticleKey state;
+
+ ParticleSimulationData sim;
+ sim.scene = m_scene;
+ sim.ob = m_object;
+ sim.psys = m_psys;
+
+ m_psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+
+ uint64_t index = 0;
+ for (int p = 0; p < m_psys->totpart; p++) {
+ float pos[3], vel[3];
+
+ if (m_psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
+ continue;
+ }
+
+ state.time = BKE_scene_frame_get(m_scene);
+
+ if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
+ continue;
+ }
+
+ /* location */
+ mul_v3_m4v3(pos, m_object->imat, state.co);
+
+ /* velocity */
+ sub_v3_v3v3(vel, state.co, m_psys->particles[p].prev_state.co);
+
+ /* Convert Z-up to Y-up. */
+ points.push_back(Imath::V3f(pos[0], pos[2], -pos[1]));
+ velocities.push_back(Imath::V3f(vel[0], vel[2], -vel[1]));
+ widths.push_back(m_psys->particles[p].size);
+ ids.push_back(index++);
+ }
+
+ if (m_psys->lattice_deform_data) {
+ end_latt_deform(m_psys->lattice_deform_data);
+ m_psys->lattice_deform_data = NULL;
+ }
+
+ Alembic::Abc::P3fArraySample psample(points);
+ Alembic::Abc::UInt64ArraySample idsample(ids);
+ Alembic::Abc::V3fArraySample vsample(velocities);
+ Alembic::Abc::FloatArraySample wsample_array(widths);
+ Alembic::AbcGeom::OFloatGeomParam::Sample wsample(wsample_array, kVertexScope);
+
+ m_sample = OPointsSchema::Sample(psample, idsample, vsample, wsample);
+ m_sample.setSelfBounds(bounds());
+
+ m_schema.set(m_sample);
+}
+
+/* ************************************************************************** */
+
+AbcPointsReader::AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ IPoints ipoints(m_iobject, kWrapExisting);
+ m_schema = ipoints.getSchema();
+ get_min_max_time(m_schema, m_min_time, m_max_time);
+}
+
+bool AbcPointsReader::valid() const
+{
+ return m_schema.valid();
+}
+
+void AbcPointsReader::readObjectData(Main *bmain, float time)
+{
+ Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
+
+ const ISampleSelector sample_sel(time);
+ m_sample = m_schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = m_sample.getPositions();
+ utils::mesh_add_verts(mesh, positions->size());
+
+ CDStreamConfig config = create_config(mesh);
+ read_points_sample(m_schema, sample_sel, config, time);
+
+ if (m_settings->validate_meshes) {
+ BKE_mesh_validate(mesh, false, false);
+ }
+
+ m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
+ m_object->data = mesh;
+
+ if (has_animations(m_schema, m_settings)) {
+ addCacheModifier();
+ }
+}
+
+void read_points_sample(const IPointsSchema &schema,
+ const ISampleSelector &selector,
+ CDStreamConfig &config,
+ float time)
+{
+ Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+
+ ICompoundProperty prop = schema.getArbGeomParams();
+ N3fArraySamplePtr vnormals;
+
+ if (has_property(prop, "N")) {
+ const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", time);
+
+ if (normals_prop) {
+ vnormals = normals_prop.getValue(selector);
+ }
+ }
+
+ read_mverts(config.mvert, positions, vnormals);
+}
diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_points.h
new file mode 100644
index 00000000000..51f3103bd8b
--- /dev/null
+++ b/source/blender/alembic/intern/abc_points.h
@@ -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) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef __ABC_POINTS_H__
+#define __ABC_POINTS_H__
+
+#include "abc_object.h"
+#include "abc_customdata.h"
+
+class ParticleSystem;
+
+/* ************************************************************************** */
+
+class AbcPointsWriter : public AbcObjectWriter {
+ Alembic::AbcGeom::OPointsSchema m_schema;
+ Alembic::AbcGeom::OPointsSchema::Sample m_sample;
+ ParticleSystem *m_psys;
+
+public:
+ AbcPointsWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings,
+ ParticleSystem *psys);
+
+ void do_write();
+};
+
+/* ************************************************************************** */
+
+class AbcPointsReader : public AbcObjectReader {
+ Alembic::AbcGeom::IPointsSchema m_schema;
+ Alembic::AbcGeom::IPointsSchema::Sample m_sample;
+
+public:
+ AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+};
+
+void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,
+ const Alembic::AbcGeom::ISampleSelector &selector,
+ CDStreamConfig &config,
+ float time);
+
+#endif /* __ABC_POINTS_H__ */
diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc
new file mode 100644
index 00000000000..3326ae0ed84
--- /dev/null
+++ b/source/blender/alembic/intern/abc_transform.cc
@@ -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.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_transform.h"
+
+#include <OpenEXR/ImathBoxAlgo.h>
+
+#include "abc_util.h"
+
+extern "C" {
+#include "DNA_object_types.h"
+
+#include "BLI_math.h"
+
+#include "BKE_object.h"
+}
+
+using Alembic::AbcGeom::OObject;
+using Alembic::AbcGeom::OXform;
+
+/* ************************************************************************** */
+
+static bool has_parent_camera(Object *ob)
+{
+ if (!ob->parent) {
+ return false;
+ }
+
+ Object *parent = ob->parent;
+
+ if (parent->type == OB_CAMERA) {
+ return true;
+ }
+
+ return has_parent_camera(parent);
+}
+
+/* ************************************************************************** */
+
+AbcTransformWriter::AbcTransformWriter(Object *ob,
+ const OObject &abc_parent,
+ AbcTransformWriter *parent,
+ unsigned int time_sampling,
+ ExportSettings &settings)
+ : AbcObjectWriter(NULL, ob, time_sampling, settings, parent)
+{
+ m_is_animated = hasAnimation(m_object);
+ m_parent = NULL;
+
+ if (!m_is_animated) {
+ time_sampling = 0;
+ }
+
+ m_xform = OXform(abc_parent, get_id_name(m_object), time_sampling);
+ m_schema = m_xform.getSchema();
+}
+
+void AbcTransformWriter::do_write()
+{
+ if (m_first_frame) {
+ m_visibility = Alembic::AbcGeom::CreateVisibilityProperty(m_xform, m_xform.getSchema().getTimeSampling());
+ }
+
+ m_visibility.set(!(m_object->restrictflag & OB_RESTRICT_VIEW));
+
+ if (!m_first_frame && !m_is_animated) {
+ return;
+ }
+
+ float mat[4][4];
+ create_transform_matrix(m_object, mat);
+
+ /* Only apply rotation to root camera, parenting will propagate it. */
+ if (m_object->type == OB_CAMERA && !has_parent_camera(m_object)) {
+ float rot_mat[4][4];
+ unit_m4(rot_mat);
+ rotate_m4(rot_mat, 'X', -M_PI_2);
+ mul_m4_m4m4(mat, mat, rot_mat);
+ }
+
+ if (!m_object->parent) {
+ /* Only apply scaling to root objects, parenting will propagate it. */
+ float scale_mat[4][4];
+ scale_m4_fl(scale_mat, m_settings.global_scale);
+ mul_m4_m4m4(mat, mat, scale_mat);
+ mul_v3_fl(mat[3], m_settings.global_scale);
+ }
+
+ m_matrix = convert_matrix(mat);
+
+ m_sample.setMatrix(m_matrix);
+ m_schema.set(m_sample);
+}
+
+Imath::Box3d AbcTransformWriter::bounds()
+{
+ Imath::Box3d bounds;
+
+ for (int i = 0; i < m_children.size(); ++i) {
+ Imath::Box3d box(m_children[i]->bounds());
+ bounds.extendBy(box);
+ }
+
+ return Imath::transform(bounds, m_matrix);
+}
+
+bool AbcTransformWriter::hasAnimation(Object */*ob*/) const
+{
+ /* TODO(kevin): implement this. */
+ return true;
+}
+
+/* ************************************************************************** */
+
+AbcEmptyReader::AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ Alembic::AbcGeom::IXform xform(object, Alembic::AbcGeom::kWrapExisting);
+ m_schema = xform.getSchema();
+
+ get_min_max_time(m_schema, m_min_time, m_max_time);
+}
+
+bool AbcEmptyReader::valid() const
+{
+ return m_schema.valid();
+}
+
+void AbcEmptyReader::readObjectData(Main *bmain, float /*time*/)
+{
+ m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str());
+ m_object->data = NULL;
+}
diff --git a/source/blender/alembic/intern/abc_transform.h b/source/blender/alembic/intern/abc_transform.h
new file mode 100644
index 00000000000..6a3aae216f2
--- /dev/null
+++ b/source/blender/alembic/intern/abc_transform.h
@@ -0,0 +1,73 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_TRANSFORM_H__
+#define __ABC_TRANSFORM_H__
+
+#include "abc_object.h"
+
+#include <Alembic/AbcGeom/All.h>
+
+/* ************************************************************************** */
+
+class AbcTransformWriter : public AbcObjectWriter {
+ Alembic::AbcGeom::OXform m_xform;
+ Alembic::AbcGeom::OXformSchema m_schema;
+ Alembic::AbcGeom::XformSample m_sample;
+ Alembic::AbcGeom::OVisibilityProperty m_visibility;
+ Alembic::Abc::M44d m_matrix;
+
+ bool m_is_animated;
+ Object *m_parent;
+ bool m_visible;
+
+public:
+ AbcTransformWriter(Object *ob,
+ const Alembic::AbcGeom::OObject &abc_parent,
+ AbcTransformWriter *parent,
+ unsigned int time_sampling,
+ ExportSettings &settings);
+
+ Alembic::AbcGeom::OXform &alembicXform() { return m_xform;}
+ virtual Imath::Box3d bounds();
+ void setParent(Object *p) { m_parent = p; }
+
+private:
+ virtual void do_write();
+
+ bool hasAnimation(Object *ob) const;
+};
+
+/* ************************************************************************** */
+
+class AbcEmptyReader : public AbcObjectReader {
+ Alembic::AbcGeom::IXformSchema m_schema;
+
+public:
+ AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+};
+
+#endif /* __ABC_TRANSFORM_H__ */
diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc
new file mode 100644
index 00000000000..fbab0bcdf34
--- /dev/null
+++ b/source/blender/alembic/intern/abc_util.cc
@@ -0,0 +1,437 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_util.h"
+
+#include <algorithm>
+
+extern "C" {
+#include "DNA_object_types.h"
+
+#include "BLI_math.h"
+}
+
+std::string get_id_name(Object *ob)
+{
+ if (!ob) {
+ return "";
+ }
+
+ return get_id_name(&ob->id);
+}
+
+std::string get_id_name(ID *id)
+{
+ std::string name(id->name + 2);
+ std::replace(name.begin(), name.end(), ' ', '_');
+ std::replace(name.begin(), name.end(), '.', '_');
+ std::replace(name.begin(), name.end(), ':', '_');
+
+ return name;
+}
+
+std::string get_object_dag_path_name(Object *ob, Object *dupli_parent)
+{
+ std::string name = get_id_name(ob);
+
+ Object *p = ob->parent;
+
+ while (p) {
+ name = get_id_name(p) + "/" + name;
+ p = p->parent;
+ }
+
+ if (dupli_parent && (ob != dupli_parent)) {
+ name = get_id_name(dupli_parent) + "/" + name;
+ }
+
+ return name;
+}
+
+bool object_selected(Object *ob)
+{
+ return ob->flag & SELECT;
+}
+
+bool parent_selected(Object *ob)
+{
+ if (object_selected(ob)) {
+ return true;
+ }
+
+ bool do_export = false;
+
+ Object *parent = ob->parent;
+
+ while (parent != NULL) {
+ if (object_selected(parent)) {
+ do_export = true;
+ break;
+ }
+
+ parent = parent->parent;
+ }
+
+ return do_export;
+}
+
+Imath::M44d convert_matrix(float mat[4][4])
+{
+ Imath::M44d m;
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ m[i][j] = mat[i][j];
+ }
+ }
+
+ return m;
+}
+
+void split(const std::string &s, const char delim, std::vector<std::string> &tokens)
+{
+ tokens.clear();
+
+ std::stringstream ss(s);
+ std::string item;
+
+ while (std::getline(ss, item, delim)) {
+ if (!item.empty()) {
+ tokens.push_back(item);
+ }
+ }
+}
+
+/* Create a rotation matrix for each axis from euler angles.
+ * Euler angles are swaped to change coordinate system. */
+static void create_rotation_matrix(
+ float rot_x_mat[3][3], float rot_y_mat[3][3],
+ float rot_z_mat[3][3], const float euler[3], const bool to_yup)
+{
+ const float rx = euler[0];
+ const float ry = (to_yup) ? euler[2] : -euler[2];
+ const float rz = (to_yup) ? -euler[1] : euler[1];
+
+ unit_m3(rot_x_mat);
+ unit_m3(rot_y_mat);
+ unit_m3(rot_z_mat);
+
+ rot_x_mat[1][1] = cos(rx);
+ rot_x_mat[2][1] = -sin(rx);
+ rot_x_mat[1][2] = sin(rx);
+ rot_x_mat[2][2] = cos(rx);
+
+ rot_y_mat[2][2] = cos(ry);
+ rot_y_mat[0][2] = -sin(ry);
+ rot_y_mat[2][0] = sin(ry);
+ rot_y_mat[0][0] = cos(ry);
+
+ rot_z_mat[0][0] = cos(rz);
+ rot_z_mat[1][0] = -sin(rz);
+ rot_z_mat[0][1] = sin(rz);
+ rot_z_mat[1][1] = cos(rz);
+}
+
+/* Recompute transform matrix of object in new coordinate system
+ * (from Y-Up to Z-Up). */
+void create_transform_matrix(float r_mat[4][4])
+{
+ float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], transform_mat[4][4];
+ float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
+ float loc[3], scale[3], euler[3];
+
+ zero_v3(loc);
+ zero_v3(scale);
+ zero_v3(euler);
+ unit_m3(rot);
+ unit_m3(rot_mat);
+ unit_m4(scale_mat);
+ unit_m4(transform_mat);
+ unit_m4(invmat);
+
+ /* Compute rotation matrix. */
+
+ /* Extract location, rotation, and scale from matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, r_mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, false);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+
+ /* Add rotation matrix to transformation matrix. */
+ copy_m4_m3(transform_mat, rot_mat);
+
+ /* Add translation to transformation matrix. */
+ copy_yup_zup(transform_mat[3], loc);
+
+ /* Create scale matrix. */
+ scale_mat[0][0] = scale[0];
+ scale_mat[1][1] = scale[2];
+ scale_mat[2][2] = scale[1];
+
+ /* Add scale to transformation matrix. */
+ mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
+
+ copy_m4_m4(r_mat, transform_mat);
+}
+
+void create_input_transform(const Alembic::AbcGeom::ISampleSelector &sample_sel,
+ const Alembic::AbcGeom::IXform &ixform, Object *ob,
+ float r_mat[4][4], float scale, bool has_alembic_parent)
+{
+
+ const Alembic::AbcGeom::IXformSchema &ixform_schema = ixform.getSchema();
+ Alembic::AbcGeom::XformSample xs;
+ ixform_schema.get(xs, sample_sel);
+ const Imath::M44d &xform = xs.getMatrix();
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ r_mat[i][j] = xform[i][j];
+ }
+ }
+
+ if (ob->type == OB_CAMERA) {
+ float cam_to_yup[4][4];
+ unit_m4(cam_to_yup);
+ rotate_m4(cam_to_yup, 'X', M_PI_2);
+ mul_m4_m4m4(r_mat, r_mat, cam_to_yup);
+ }
+
+ create_transform_matrix(r_mat);
+
+ if (ob->parent) {
+ mul_m4_m4m4(r_mat, ob->parent->obmat, r_mat);
+ }
+ /* TODO(kevin) */
+ else if (!has_alembic_parent) {
+ /* Only apply scaling to root objects, parenting will propagate it. */
+ float scale_mat[4][4];
+ scale_m4_fl(scale_mat, scale);
+ mul_m4_m4m4(r_mat, r_mat, scale_mat);
+ mul_v3_fl(r_mat[3], scale);
+ }
+}
+
+/* Recompute transform matrix of object in new coordinate system (from Z-Up to Y-Up). */
+void create_transform_matrix(Object *obj, float transform_mat[4][4])
+{
+ float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], mat[4][4];
+ float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
+ float loc[3], scale[3], euler[3];
+
+ zero_v3(loc);
+ zero_v3(scale);
+ zero_v3(euler);
+ unit_m3(rot);
+ unit_m3(rot_mat);
+ unit_m4(scale_mat);
+ unit_m4(transform_mat);
+ unit_m4(invmat);
+ unit_m4(mat);
+
+ /* get local matrix. */
+ if (obj->parent) {
+ invert_m4_m4(invmat, obj->parent->obmat);
+ mul_m4_m4m4(mat, invmat, obj->obmat);
+ }
+ else {
+ copy_m4_m4(mat, obj->obmat);
+ }
+
+ /* Compute rotation matrix. */
+ switch (obj->rotmode) {
+ case ROT_MODE_AXISANGLE:
+ {
+ /* Get euler angles from axis angle rotation. */
+ axis_angle_to_eulO(euler, ROT_MODE_XYZ, obj->rotAxis, obj->rotAngle);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+
+ /* Extract location and scale from matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ break;
+ }
+ case ROT_MODE_QUAT:
+ {
+ float q[4];
+ copy_v4_v4(q, obj->quat);
+
+ /* Swap axis. */
+ q[2] = obj->quat[3];
+ q[3] = -obj->quat[2];
+
+ /* Compute rotation matrix from quaternion. */
+ quat_to_mat3(rot_mat, q);
+
+ /* Extract location and scale from matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ break;
+ }
+ case ROT_MODE_XYZ:
+ {
+ /* Extract location, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+
+ break;
+ }
+ case ROT_MODE_XZY:
+ {
+ /* Extract location, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_XZY, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+
+ break;
+ }
+ case ROT_MODE_YXZ:
+ {
+ /* Extract location, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_YXZ, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+
+ break;
+ }
+ case ROT_MODE_YZX:
+ {
+ /* Extract location, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_YZX, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+
+ break;
+ }
+ case ROT_MODE_ZXY:
+ {
+ /* Extract location, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_ZXY, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+
+ break;
+ }
+ case ROT_MODE_ZYX:
+ {
+ /* Extract location, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_ZYX, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+
+ break;
+ }
+ }
+
+ /* Add rotation matrix to transformation matrix. */
+ copy_m4_m3(transform_mat, rot_mat);
+
+ /* Add translation to transformation matrix. */
+ copy_zup_yup(transform_mat[3], loc);
+
+ /* Create scale matrix. */
+ scale_mat[0][0] = scale[0];
+ scale_mat[1][1] = scale[2];
+ scale_mat[2][2] = scale[1];
+
+ /* Add scale to transformation matrix. */
+ mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
+}
+
+bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
+{
+ if (!prop.valid()) {
+ return false;
+ }
+
+ return prop.getPropertyHeader(name) != NULL;
+}
diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h
new file mode 100644
index 00000000000..688a25d85f6
--- /dev/null
+++ b/source/blender/alembic/intern/abc_util.h
@@ -0,0 +1,125 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_UTIL_H__
+#define __ABC_UTIL_H__
+
+#include <Alembic/Abc/All.h>
+#include <Alembic/AbcGeom/All.h>
+
+#ifdef _MSC_VER
+# define ABC_INLINE static __forceinline
+#else
+# define ABC_INLINE static inline
+#endif
+
+using Alembic::Abc::chrono_t;
+
+class ImportSettings;
+
+struct ID;
+struct Object;
+
+std::string get_id_name(ID *id);
+std::string get_id_name(Object *ob);
+std::string get_object_dag_path_name(Object *ob, Object *dupli_parent);
+
+bool object_selected(Object *ob);
+bool parent_selected(Object *ob);
+
+Imath::M44d convert_matrix(float mat[4][4]);
+void create_transform_matrix(float r_mat[4][4]);
+void create_transform_matrix(Object *obj, float transform_mat[4][4]);
+
+void split(const std::string &s, const char delim, std::vector<std::string> &tokens);
+
+template<class TContainer>
+bool begins_with(const TContainer &input, const TContainer &match)
+{
+ return input.size() >= match.size()
+ && std::equal(match.begin(), match.end(), input.begin());
+}
+
+void create_input_transform(const Alembic::AbcGeom::ISampleSelector &sample_sel,
+ const Alembic::AbcGeom::IXform &ixform, Object *ob,
+ float r_mat[4][4], float scale, bool has_alembic_parent = false);
+
+template <typename Schema>
+void get_min_max_time(const Schema &schema, chrono_t &min, chrono_t &max)
+{
+ const Alembic::Abc::TimeSamplingPtr &time_samp = schema.getTimeSampling();
+
+ if (!schema.isConstant()) {
+ const size_t num_samps = schema.getNumSamples();
+
+ if (num_samps > 0) {
+ const chrono_t min_time = time_samp->getSampleTime(0);
+ min = std::min(min, min_time);
+
+ const chrono_t max_time = time_samp->getSampleTime(num_samps - 1);
+ max = std::max(max, max_time);
+ }
+ }
+}
+
+bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name);
+
+/* ************************** */
+
+/* TODO(kevin): for now keeping these transformations hardcoded to make sure
+ * everything works properly, and also because Alembic is almost exclusively
+ * used in Y-up software, but eventually they'll be set by the user in the UI
+ * like other importers/exporters do, to support other axis. */
+
+/* Copy from Y-up to Z-up. */
+
+ABC_INLINE void copy_yup_zup(float zup[3], const float yup[3])
+{
+ zup[0] = yup[0];
+ zup[1] = -yup[2];
+ zup[2] = yup[1];
+}
+
+ABC_INLINE void copy_yup_zup(short zup[3], const short yup[3])
+{
+ zup[0] = yup[0];
+ zup[1] = -yup[2];
+ zup[2] = yup[1];
+}
+
+/* Copy from Z-up to Y-up. */
+
+ABC_INLINE void copy_zup_yup(float yup[3], const float zup[3])
+{
+ yup[0] = zup[0];
+ yup[1] = zup[2];
+ yup[2] = -zup[1];
+}
+
+ABC_INLINE void copy_zup_yup(short yup[3], const short zup[3])
+{
+ yup[0] = zup[0];
+ yup[1] = zup[2];
+ yup[2] = -zup[1];
+}
+
+#endif /* __ABC_UTIL_H__ */
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
new file mode 100644
index 00000000000..0e96ac22e11
--- /dev/null
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -0,0 +1,1136 @@
+/*
+ * ***** 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): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../ABC_alembic.h"
+
+#ifdef WITH_ALEMBIC_HDF5
+# include <Alembic/AbcCoreHDF5/All.h>
+#endif
+
+#include <Alembic/AbcCoreOgawa/All.h>
+#include <Alembic/AbcMaterial/IMaterial.h>
+
+#include "abc_camera.h"
+#include "abc_curves.h"
+#include "abc_hair.h"
+#include "abc_mesh.h"
+#include "abc_nurbs.h"
+#include "abc_points.h"
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "DNA_cachefile_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_cachefile.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+/* SpaceType struct has a member called 'new' which obviously conflicts with C++
+ * so temporarily redefining the new keyword to make it compile. */
+#define new extern_new
+#include "BKE_screen.h"
+#undef new
+
+#include "BLI_fileops.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+}
+
+using Alembic::Abc::Int32ArraySamplePtr;
+using Alembic::Abc::ObjectHeader;
+
+using Alembic::AbcGeom::ErrorHandler;
+using Alembic::AbcGeom::Exception;
+using Alembic::AbcGeom::MetaData;
+using Alembic::AbcGeom::P3fArraySamplePtr;
+using Alembic::AbcGeom::kWrapExisting;
+
+using Alembic::AbcGeom::IArchive;
+using Alembic::AbcGeom::ICamera;
+using Alembic::AbcGeom::ICurves;
+using Alembic::AbcGeom::ICurvesSchema;
+using Alembic::AbcGeom::IFaceSet;
+using Alembic::AbcGeom::ILight;
+using Alembic::AbcGeom::INuPatch;
+using Alembic::AbcGeom::IObject;
+using Alembic::AbcGeom::IPoints;
+using Alembic::AbcGeom::IPointsSchema;
+using Alembic::AbcGeom::IPolyMesh;
+using Alembic::AbcGeom::IPolyMeshSchema;
+using Alembic::AbcGeom::ISampleSelector;
+using Alembic::AbcGeom::ISubD;
+using Alembic::AbcGeom::IV2fGeomParam;
+using Alembic::AbcGeom::IXform;
+using Alembic::AbcGeom::IXformSchema;
+using Alembic::AbcGeom::N3fArraySamplePtr;
+using Alembic::AbcGeom::XformSample;
+using Alembic::AbcGeom::ICompoundProperty;
+using Alembic::AbcGeom::IN3fArrayProperty;
+using Alembic::AbcGeom::IN3fGeomParam;
+using Alembic::AbcGeom::V3fArraySamplePtr;
+
+using Alembic::AbcMaterial::IMaterial;
+
+struct AbcArchiveHandle {
+ int unused;
+};
+
+ABC_INLINE IArchive *archive_from_handle(AbcArchiveHandle *handle)
+{
+ return reinterpret_cast<IArchive *>(handle);
+}
+
+ABC_INLINE AbcArchiveHandle *handle_from_archive(IArchive *archive)
+{
+ return reinterpret_cast<AbcArchiveHandle *>(archive);
+}
+
+static IArchive *open_archive(const std::string &filename)
+{
+ Alembic::AbcCoreAbstract::ReadArraySampleCachePtr cache_ptr;
+ IArchive *archive;
+
+ try {
+ archive = new IArchive(Alembic::AbcCoreOgawa::ReadArchive(),
+ filename.c_str(), ErrorHandler::kThrowPolicy,
+ cache_ptr);
+ }
+ catch (const Exception &e) {
+ std::cerr << e.what() << '\n';
+
+#ifdef WITH_ALEMBIC_HDF5
+ try {
+ archive = new IArchive(Alembic::AbcCoreHDF5::ReadArchive(),
+ filename.c_str(), ErrorHandler::kThrowPolicy,
+ cache_ptr);
+ }
+ catch (const Exception &) {
+ std::cerr << e.what() << '\n';
+ return NULL;
+ }
+#else
+ return NULL;
+#endif
+ }
+
+ return archive;
+}
+
+//#define USE_NURBS
+
+/* NOTE: this function is similar to visit_objects below, need to keep them in
+ * sync. */
+static void gather_objects_paths(const IObject &object, ListBase *object_paths)
+{
+ if (!object.valid()) {
+ return;
+ }
+
+ for (int i = 0; i < object.getNumChildren(); ++i) {
+ IObject child = object.getChild(i);
+
+ if (!child.valid()) {
+ continue;
+ }
+
+ bool get_path = false;
+
+ const MetaData &md = child.getMetaData();
+
+ if (IXform::matches(md)) {
+ /* Check whether or not this object is a Maya locator, which is
+ * similar to empties used as parent object in Blender. */
+ if (has_property(child.getProperties(), "locator")) {
+ get_path = true;
+ }
+ else {
+ /* Avoid creating an empty object if the child of this transform
+ * is not a transform (that is an empty). */
+ if (child.getNumChildren() == 1) {
+ if (IXform::matches(child.getChild(0).getMetaData())) {
+ get_path = true;
+ }
+#if 0
+ else {
+ std::cerr << "Skipping " << child.getFullName() << '\n';
+ }
+#endif
+ }
+ else {
+ get_path = true;
+ }
+ }
+ }
+ else if (IPolyMesh::matches(md)) {
+ get_path = true;
+ }
+ else if (ISubD::matches(md)) {
+ get_path = true;
+ }
+ else if (INuPatch::matches(md)) {
+#ifdef USE_NURBS
+ get_path = true;
+#endif
+ }
+ else if (ICamera::matches(md)) {
+ get_path = true;
+ }
+ else if (IPoints::matches(md)) {
+ get_path = true;
+ }
+ else if (IMaterial::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (ILight::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (IFaceSet::matches(md)) {
+ /* Pass, those are handled in the mesh reader. */
+ }
+ else if (ICurves::matches(md)) {
+ get_path = true;
+ }
+ else {
+ assert(false);
+ }
+
+ if (get_path) {
+ AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
+ MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
+
+ BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX);
+
+ BLI_addtail(object_paths, abc_path);
+ }
+
+ gather_objects_paths(child, object_paths);
+ }
+}
+
+AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths)
+{
+ IArchive *archive = open_archive(filename);
+
+ if (!archive) {
+ return NULL;
+ }
+
+ if (object_paths) {
+ gather_objects_paths(archive->getTop(), object_paths);
+ }
+
+ return handle_from_archive(archive);
+}
+
+void ABC_free_handle(AbcArchiveHandle *handle)
+{
+ delete archive_from_handle(handle);
+}
+
+int ABC_get_version()
+{
+ return ALEMBIC_LIBRARY_VERSION;
+}
+
+static void find_iobject(const IObject &object, IObject &ret,
+ const std::string &path)
+{
+ if (!object.valid()) {
+ return;
+ }
+
+ std::vector<std::string> tokens;
+ split(path, '/', tokens);
+
+ IObject tmp = object;
+
+ std::vector<std::string>::iterator iter;
+ for (iter = tokens.begin(); iter != tokens.end(); ++iter) {
+ IObject child = tmp.getChild(*iter);
+ tmp = child;
+ }
+
+ ret = tmp;
+}
+
+struct ExportJobData {
+ Scene *scene;
+ Main *bmain;
+
+ char filename[1024];
+ ExportSettings settings;
+
+ short *stop;
+ short *do_update;
+ float *progress;
+
+ bool was_canceled;
+};
+
+static void export_startjob(void *customdata, short *stop, short *do_update, float *progress)
+{
+ ExportJobData *data = static_cast<ExportJobData *>(customdata);
+
+ data->stop = stop;
+ data->do_update = do_update;
+ data->progress = progress;
+
+ /* XXX annoying hack: needed to prevent data corruption when changing
+ * scene frame in separate threads
+ */
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
+
+ G.is_break = false;
+
+ try {
+ Scene *scene = data->scene;
+ AbcExporter exporter(scene, data->filename, data->settings);
+
+ const int orig_frame = CFRA;
+
+ data->was_canceled = false;
+ exporter(data->bmain, *data->progress, data->was_canceled);
+
+ if (CFRA != orig_frame) {
+ CFRA = orig_frame;
+
+ BKE_scene_update_for_newframe(data->bmain->eval_ctx, data->bmain,
+ scene, scene->lay);
+ }
+ }
+ catch (const std::exception &e) {
+ std::cerr << "Abc Export error: " << e.what() << '\n';
+ }
+ catch (...) {
+ std::cerr << "Abc Export error\n";
+ }
+}
+
+static void export_endjob(void *customdata)
+{
+ ExportJobData *data = static_cast<ExportJobData *>(customdata);
+
+ if (data->was_canceled && BLI_exists(data->filename)) {
+ BLI_delete(data->filename, false, false);
+ }
+
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
+}
+
+void ABC_export(
+ Scene *scene,
+ bContext *C,
+ const char *filepath,
+ const struct AlembicExportParams *params)
+{
+ ExportJobData *job = static_cast<ExportJobData *>(MEM_mallocN(sizeof(ExportJobData), "ExportJobData"));
+ job->scene = scene;
+ job->bmain = CTX_data_main(C);
+ BLI_strncpy(job->filename, filepath, 1024);
+
+ job->settings.scene = job->scene;
+ job->settings.frame_start = params->frame_start;
+ job->settings.frame_end = params->frame_end;
+ job->settings.frame_step_xform = params->frame_step_xform;
+ job->settings.frame_step_shape = params->frame_step_shape;
+ job->settings.shutter_open = params->shutter_open;
+ job->settings.shutter_close = params->shutter_close;
+ job->settings.selected_only = params->selected_only;
+ job->settings.export_face_sets = params->face_sets;
+ job->settings.export_normals = params->normals;
+ job->settings.export_uvs = params->uvs;
+ job->settings.export_vcols = params->vcolors;
+ job->settings.apply_subdiv = params->apply_subdiv;
+ job->settings.flatten_hierarchy = params->flatten_hierarchy;
+ job->settings.visible_layers_only = params->visible_layers_only;
+ job->settings.renderable_only = params->renderable_only;
+ job->settings.use_subdiv_schema = params->use_subdiv_schema;
+ job->settings.export_ogawa = (params->compression_type == ABC_ARCHIVE_OGAWA);
+ job->settings.pack_uv = params->packuv;
+ job->settings.global_scale = params->global_scale;
+
+ if (job->settings.frame_start > job->settings.frame_end) {
+ std::swap(job->settings.frame_start, job->settings.frame_end);
+ }
+
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ job->scene,
+ "Alembic Export",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_ALEMBIC);
+
+ /* setup job */
+ WM_jobs_customdata_set(wm_job, job, MEM_freeN);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
+ WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+}
+
+/* ********************** Import file ********************** */
+
+static void visit_object(const IObject &object,
+ std::vector<AbcObjectReader *> &readers,
+ GHash *parent_map,
+ ImportSettings &settings)
+{
+ if (!object.valid()) {
+ return;
+ }
+
+ for (int i = 0; i < object.getNumChildren(); ++i) {
+ IObject child = object.getChild(i);
+
+ if (!child.valid()) {
+ continue;
+ }
+
+ AbcObjectReader *reader = NULL;
+
+ const MetaData &md = child.getMetaData();
+
+ if (IXform::matches(md)) {
+ bool create_xform = false;
+
+ /* Check whether or not this object is a Maya locator, which is
+ * similar to empties used as parent object in Blender. */
+ if (has_property(child.getProperties(), "locator")) {
+ create_xform = true;
+ }
+ else {
+ /* Avoid creating an empty object if the child of this transform
+ * is not a transform (that is an empty). */
+ if (child.getNumChildren() == 1) {
+ if (IXform::matches(child.getChild(0).getMetaData())) {
+ create_xform = true;
+ }
+#if 0
+ else {
+ std::cerr << "Skipping " << child.getFullName() << '\n';
+ }
+#endif
+ }
+ else {
+ create_xform = true;
+ }
+ }
+
+ if (create_xform) {
+ reader = new AbcEmptyReader(child, settings);
+ }
+ }
+ else if (IPolyMesh::matches(md)) {
+ reader = new AbcMeshReader(child, settings);
+ }
+ else if (ISubD::matches(md)) {
+ reader = new AbcSubDReader(child, settings);
+ }
+ else if (INuPatch::matches(md)) {
+#ifdef USE_NURBS
+ /* TODO(kevin): importing cyclic NURBS from other software crashes
+ * at the moment. This is due to the fact that NURBS in other
+ * software have duplicated points which causes buffer overflows in
+ * Blender. Need to figure out exactly how these points are
+ * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
+ * Until this is fixed, disabling NURBS reading. */
+ reader = new AbcNurbsReader(child, settings);
+#endif
+ }
+ else if (ICamera::matches(md)) {
+ reader = new AbcCameraReader(child, settings);
+ }
+ else if (IPoints::matches(md)) {
+ reader = new AbcPointsReader(child, settings);
+ }
+ else if (IMaterial::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (ILight::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (IFaceSet::matches(md)) {
+ /* Pass, those are handled in the mesh reader. */
+ }
+ else if (ICurves::matches(md)) {
+ reader = new AbcCurveReader(child, settings);
+ }
+ else {
+ assert(false);
+ }
+
+ if (reader) {
+ readers.push_back(reader);
+
+ AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
+ MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
+
+ BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX);
+
+ BLI_addtail(&settings.cache_file->object_paths, abc_path);
+
+ /* Cast to `void *` explicitly to avoid compiler errors because it
+ * is a `const char *` which the compiler cast to `const void *`
+ * instead of the expected `void *`. */
+ BLI_ghash_insert(parent_map, (void *)child.getFullName().c_str(), reader);
+ }
+
+ visit_object(child, readers, parent_map, settings);
+ }
+}
+
+enum {
+ ABC_NO_ERROR = 0,
+ ABC_ARCHIVE_FAIL,
+};
+
+struct ImportJobData {
+ Main *bmain;
+ Scene *scene;
+
+ char filename[1024];
+ ImportSettings settings;
+
+ GHash *parent_map;
+ std::vector<AbcObjectReader *> readers;
+
+ short *stop;
+ short *do_update;
+ float *progress;
+
+ char error_code;
+ bool was_cancelled;
+};
+
+ABC_INLINE bool is_mesh_and_strands(const IObject &object)
+{
+ if (object.getNumChildren() != 2) {
+ return false;
+ }
+
+ bool has_mesh = false;
+ bool has_curve = false;
+
+ for (int i = 0; i < object.getNumChildren(); ++i) {
+ const IObject &child = object.getChild(i);
+
+ if (!child.valid()) {
+ continue;
+ }
+
+ const MetaData &md = child.getMetaData();
+
+ if (IPolyMesh::matches(md)) {
+ has_mesh = true;
+ }
+ else if (ISubD::matches(md)) {
+ has_mesh = true;
+ }
+ else if (ICurves::matches(md)) {
+ has_curve = true;
+ }
+ }
+
+ return has_mesh && has_curve;
+}
+
+static void import_startjob(void *user_data, short *stop, short *do_update, float *progress)
+{
+ ImportJobData *data = static_cast<ImportJobData *>(user_data);
+
+ data->stop = stop;
+ data->do_update = do_update;
+ data->progress = progress;
+
+ IArchive *archive = open_archive(data->filename);
+
+ if (!archive || !archive->valid()) {
+ data->error_code = ABC_ARCHIVE_FAIL;
+ return;
+ }
+
+ CacheFile *cache_file = static_cast<CacheFile *>(BKE_cachefile_add(data->bmain, BLI_path_basename(data->filename)));
+
+ /* Decrement the ID ref-count because it is going to be incremented for each
+ * modifier and constraint that it will be attached to, so since currently
+ * it is not used by anyone, its use count will off by one. */
+ id_us_min(&cache_file->id);
+
+ cache_file->is_sequence = data->settings.is_sequence;
+ cache_file->scale = data->settings.scale;
+ cache_file->handle = handle_from_archive(archive);
+ BLI_strncpy(cache_file->filepath, data->filename, 1024);
+
+ data->settings.cache_file = cache_file;
+
+ *data->do_update = true;
+ *data->progress = 0.05f;
+
+ data->parent_map = BLI_ghash_str_new("alembic parent ghash");
+
+ /* Parse Alembic Archive. */
+
+ visit_object(archive->getTop(), data->readers, data->parent_map, data->settings);
+
+ if (G.is_break) {
+ data->was_cancelled = true;
+ return;
+ }
+
+ *data->do_update = true;
+ *data->progress = 0.1f;
+
+ /* Create objects and set scene frame range. */
+
+ const float size = static_cast<float>(data->readers.size());
+ size_t i = 0;
+
+ chrono_t min_time = std::numeric_limits<chrono_t>::max();
+ chrono_t max_time = std::numeric_limits<chrono_t>::min();
+
+ std::vector<AbcObjectReader *>::iterator iter;
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ AbcObjectReader *reader = *iter;
+
+ if (reader->valid()) {
+ reader->readObjectData(data->bmain, 0.0f);
+ reader->readObjectMatrix(0.0f);
+
+ min_time = std::min(min_time, reader->minTime());
+ max_time = std::max(max_time, reader->maxTime());
+ }
+
+ *data->progress = 0.1f + 0.6f * (++i / size);
+ *data->do_update = true;
+
+ if (G.is_break) {
+ data->was_cancelled = true;
+ return;
+ }
+ }
+
+ if (data->settings.set_frame_range) {
+ Scene *scene = data->scene;
+
+ if (data->settings.is_sequence) {
+ SFRA = data->settings.offset;
+ EFRA = SFRA + (data->settings.sequence_len - 1);
+ CFRA = SFRA;
+ }
+ else if (min_time < max_time) {
+ SFRA = min_time * FPS;
+ EFRA = max_time * FPS;
+ CFRA = SFRA;
+ }
+ }
+
+ /* Setup parentship. */
+
+ i = 0;
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ const AbcObjectReader *reader = *iter;
+ const AbcObjectReader *parent_reader = NULL;
+ const IObject &iobject = reader->iobject();
+
+ IObject parent = iobject.getParent();
+
+ if (!IXform::matches(iobject.getHeader())) {
+ /* In the case of an non XForm node, the parent is the transform
+ * matrix of the data itself, so we get the its grand parent.
+ */
+
+ /* Special case with object only containing a mesh and some strands,
+ * we want both objects to be parented to the same object. */
+ if (!is_mesh_and_strands(parent)) {
+ parent = parent.getParent();
+ }
+ }
+
+ parent_reader = reinterpret_cast<AbcObjectReader *>(
+ BLI_ghash_lookup(data->parent_map, parent.getFullName().c_str()));
+
+ if (parent_reader) {
+ Object *parent = parent_reader->object();
+
+ if (parent != NULL && reader->object() != parent) {
+ Object *ob = reader->object();
+ ob->parent = parent;
+ }
+ }
+
+ *data->progress = 0.7f + 0.3f * (++i / size);
+ *data->do_update = true;
+
+ if (G.is_break) {
+ data->was_cancelled = true;
+ return;
+ }
+ }
+}
+
+static void import_endjob(void *user_data)
+{
+ ImportJobData *data = static_cast<ImportJobData *>(user_data);
+
+ std::vector<AbcObjectReader *>::iterator iter;
+
+ /* Delete objects on cancelation. */
+ if (data->was_cancelled) {
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ Object *ob = (*iter)->object();
+
+ if (ob->data) {
+ BKE_libblock_free_us(data->bmain, ob->data);
+ ob->data = NULL;
+ }
+
+ BKE_libblock_free_us(data->bmain, ob);
+ }
+ }
+ else {
+ /* Add object to scene. */
+ BKE_scene_base_deselect_all(data->scene);
+
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ Object *ob = (*iter)->object();
+ ob->lay = data->scene->lay;
+
+ BKE_scene_base_add(data->scene, ob);
+
+ DAG_id_tag_update_ex(data->bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ }
+
+ DAG_relations_tag_update(data->bmain);
+ }
+
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ delete *iter;
+ }
+
+ if (data->parent_map) {
+ BLI_ghash_free(data->parent_map, NULL, NULL);
+ }
+
+ switch (data->error_code) {
+ default:
+ case ABC_NO_ERROR:
+ break;
+ case ABC_ARCHIVE_FAIL:
+ WM_report(RPT_ERROR, "Could not open Alembic archive for reading! See console for detail.");
+ break;
+ }
+
+ WM_main_add_notifier(NC_SCENE | ND_FRAME, data->scene);
+}
+
+static void import_freejob(void *user_data)
+{
+ ImportJobData *data = static_cast<ImportJobData *>(user_data);
+ delete data;
+}
+
+void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence, bool set_frame_range, int sequence_len, int offset, bool validate_meshes)
+{
+ /* Using new here since MEM_* funcs do not call ctor to properly initialize
+ * data. */
+ ImportJobData *job = new ImportJobData();
+ job->bmain = CTX_data_main(C);
+ job->scene = CTX_data_scene(C);
+ BLI_strncpy(job->filename, filepath, 1024);
+
+ job->settings.scale = scale;
+ job->settings.is_sequence = is_sequence;
+ job->settings.set_frame_range = set_frame_range;
+ job->settings.sequence_len = sequence_len;
+ job->settings.offset = offset;
+ job->settings.validate_meshes = validate_meshes;
+ job->parent_map = NULL;
+ job->error_code = ABC_NO_ERROR;
+ job->was_cancelled = false;
+
+ G.is_break = false;
+
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ job->scene,
+ "Alembic Import",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_ALEMBIC);
+
+ /* setup job */
+ WM_jobs_customdata_set(wm_job, job, import_freejob);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
+ WM_jobs_callbacks(wm_job, import_startjob, NULL, NULL, import_endjob);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+}
+
+/* ******************************* */
+
+void ABC_get_transform(AbcArchiveHandle *handle, Object *ob, const char *object_path, float r_mat[4][4], float time, float scale)
+{
+ IArchive *archive = archive_from_handle(handle);
+
+ if (!archive || !archive->valid()) {
+ return;
+ }
+
+ IObject tmp;
+ find_iobject(archive->getTop(), tmp, object_path);
+
+ IXform ixform;
+
+ if (IXform::matches(tmp.getHeader())) {
+ ixform = IXform(tmp, kWrapExisting);
+ }
+ else {
+ ixform = IXform(tmp.getParent(), kWrapExisting);
+ }
+
+ IXformSchema schema = ixform.getSchema();
+
+ if (!schema.valid()) {
+ return;
+ }
+
+ ISampleSelector sample_sel(time);
+
+ create_input_transform(sample_sel, ixform, ob, r_mat, scale);
+}
+
+/* ***************************************** */
+
+static bool check_smooth_poly_flag(DerivedMesh *dm)
+{
+ MPoly *mpolys = dm->getPolyArray(dm);
+
+ for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) {
+ MPoly &poly = mpolys[i];
+
+ if ((poly.flag & ME_SMOOTH) != 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void set_smooth_poly_flag(DerivedMesh *dm)
+{
+ MPoly *mpolys = dm->getPolyArray(dm);
+
+ for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) {
+ MPoly &poly = mpolys[i];
+ poly.flag |= ME_SMOOTH;
+ }
+}
+
+static void *add_customdata_cb(void *user_data, const char *name, int data_type)
+{
+ DerivedMesh *dm = static_cast<DerivedMesh *>(user_data);
+ CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
+ void *cd_ptr = NULL;
+
+ if (ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) {
+ cd_ptr = CustomData_get_layer_named(dm->getLoopDataLayout(dm), cd_data_type, name);
+
+ if (cd_ptr == NULL) {
+ cd_ptr = CustomData_add_layer_named(dm->getLoopDataLayout(dm),
+ cd_data_type,
+ CD_DEFAULT,
+ NULL,
+ dm->getNumLoops(dm),
+ name);
+ }
+ }
+
+ return cd_ptr;
+}
+
+ABC_INLINE CDStreamConfig get_config(DerivedMesh *dm)
+{
+ CDStreamConfig config;
+
+ config.user_data = dm;
+ config.mvert = dm->getVertArray(dm);
+ config.mloop = dm->getLoopArray(dm);
+ config.mpoly = dm->getPolyArray(dm);
+ config.totloop = dm->getNumLoops(dm);
+ config.totpoly = dm->getNumPolys(dm);
+ config.loopdata = dm->getLoopDataLayout(dm);
+ config.add_customdata_cb = add_customdata_cb;
+
+ return config;
+}
+
+static DerivedMesh *read_mesh_sample(DerivedMesh *dm, const IObject &iobject, const float time, int read_flag)
+{
+ IPolyMesh mesh(iobject, kWrapExisting);
+ IPolyMeshSchema schema = mesh.getSchema();
+ ISampleSelector sample_sel(time);
+ const IPolyMeshSchema::Sample sample = schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+ const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
+ const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
+
+ DerivedMesh *new_dm = NULL;
+
+ /* Only read point data when streaming meshes, unless we need to create new ones. */
+ ImportSettings settings;
+ settings.read_flag |= read_flag;
+
+ if (dm->getNumVerts(dm) != positions->size()) {
+ new_dm = CDDM_from_template(dm,
+ positions->size(),
+ 0,
+ 0,
+ face_indices->size(),
+ face_counts->size());
+
+ settings.read_flag |= MOD_MESHSEQ_READ_ALL;
+ }
+
+ CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+
+ bool has_loop_normals = false;
+ read_mesh_sample(&settings, schema, sample_sel, config, has_loop_normals);
+
+ if (new_dm) {
+ /* Check if we had ME_SMOOTH flag set to restore it. */
+ if (!has_loop_normals && check_smooth_poly_flag(dm)) {
+ set_smooth_poly_flag(new_dm);
+ }
+
+ CDDM_calc_normals(new_dm);
+ CDDM_calc_edges(new_dm);
+
+ return new_dm;
+ }
+
+ return dm;
+}
+
+using Alembic::AbcGeom::ISubDSchema;
+
+static DerivedMesh *read_subd_sample(DerivedMesh *dm, const IObject &iobject, const float time, int read_flag)
+{
+ ISubD mesh(iobject, kWrapExisting);
+ ISubDSchema schema = mesh.getSchema();
+ ISampleSelector sample_sel(time);
+ const ISubDSchema::Sample sample = schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+ const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
+ const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
+
+ DerivedMesh *new_dm = NULL;
+
+ ImportSettings settings;
+ settings.read_flag |= read_flag;
+
+ if (dm->getNumVerts(dm) != positions->size()) {
+ new_dm = CDDM_from_template(dm,
+ positions->size(),
+ 0,
+ 0,
+ face_indices->size(),
+ face_counts->size());
+
+ settings.read_flag |= MOD_MESHSEQ_READ_ALL;
+ }
+
+ /* Only read point data when streaming meshes, unless we need to create new ones. */
+ CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ read_subd_sample(&settings, schema, sample_sel, config);
+
+ if (new_dm) {
+ /* Check if we had ME_SMOOTH flag set to restore it. */
+ if (check_smooth_poly_flag(dm)) {
+ set_smooth_poly_flag(new_dm);
+ }
+
+ CDDM_calc_normals(new_dm);
+ CDDM_calc_edges(new_dm);
+
+ return new_dm;
+ }
+
+ return dm;
+}
+
+static DerivedMesh *read_points_sample(DerivedMesh *dm, const IObject &iobject, const float time)
+{
+ IPoints points(iobject, kWrapExisting);
+ IPointsSchema schema = points.getSchema();
+ ISampleSelector sample_sel(time);
+ const IPointsSchema::Sample sample = schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+
+ DerivedMesh *new_dm = NULL;
+
+ if (dm->getNumVerts(dm) != positions->size()) {
+ new_dm = CDDM_new(positions->size(), 0, 0, 0, 0);
+ }
+
+ CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ read_points_sample(schema, sample_sel, config, time);
+
+ return new_dm ? new_dm : dm;
+}
+
+/* NOTE: Alembic only stores data about control points, but the DerivedMesh
+ * passed from the cache modifier contains the displist, which has more data
+ * than the control points, so to avoid corrupting the displist we modify the
+ * object directly and create a new DerivedMesh from that. Also we might need to
+ * create new or delete existing NURBS in the curve.
+ */
+static DerivedMesh *read_curves_sample(Object *ob, const IObject &iobject, const float time)
+{
+ ICurves points(iobject, kWrapExisting);
+ ICurvesSchema schema = points.getSchema();
+ ISampleSelector sample_sel(time);
+ const ICurvesSchema::Sample sample = schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+ const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices();
+
+ int vertex_idx = 0;
+ int curve_idx = 0;
+ Curve *curve = static_cast<Curve *>(ob->data);
+
+ const int curve_count = BLI_listbase_count(&curve->nurb);
+
+ if (curve_count != num_vertices->size()) {
+ BKE_nurbList_free(&curve->nurb);
+ read_curve_sample(curve, schema, time);
+ }
+ else {
+ Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
+ for (; nurbs; nurbs = nurbs->next, ++curve_idx) {
+ const int totpoint = (*num_vertices)[curve_idx];
+
+ if (nurbs->bp) {
+ BPoint *point = nurbs->bp;
+
+ for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) {
+ const Imath::V3f &pos = (*positions)[vertex_idx];
+ copy_yup_zup(point->vec, pos.getValue());
+ }
+ }
+ else if (nurbs->bezt) {
+ BezTriple *bezier = nurbs->bezt;
+
+ for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) {
+ const Imath::V3f &pos = (*positions)[vertex_idx];
+ copy_yup_zup(bezier->vec[1], pos.getValue());
+ }
+ }
+ }
+ }
+
+ return CDDM_from_curve(ob);
+}
+
+DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle,
+ Object *ob,
+ DerivedMesh *dm,
+ const char *object_path,
+ const float time,
+ const char **err_str,
+ int read_flag)
+{
+ IArchive *archive = archive_from_handle(handle);
+
+ if (!archive || !archive->valid()) {
+ *err_str = "Invalid archive!";
+ return NULL;
+ }
+
+ IObject iobject;
+ find_iobject(archive->getTop(), iobject, object_path);
+
+ if (!iobject.valid()) {
+ *err_str = "Invalid object: verify object path";
+ return NULL;
+ }
+
+ const ObjectHeader &header = iobject.getHeader();
+
+ if (IPolyMesh::matches(header)) {
+ if (ob->type != OB_MESH) {
+ *err_str = "Object type mismatch: object path points to a mesh!";
+ return NULL;
+ }
+
+ return read_mesh_sample(dm, iobject, time, read_flag);
+ }
+ else if (ISubD::matches(header)) {
+ if (ob->type != OB_MESH) {
+ *err_str = "Object type mismatch: object path points to a subdivision mesh!";
+ return NULL;
+ }
+
+ return read_subd_sample(dm, iobject, time, read_flag);
+ }
+ else if (IPoints::matches(header)) {
+ if (ob->type != OB_MESH) {
+ *err_str = "Object type mismatch: object path points to a point cloud (requires a mesh object)!";
+ return NULL;
+ }
+
+ return read_points_sample(dm, iobject, time);
+ }
+ else if (ICurves::matches(header)) {
+ if (ob->type != OB_CURVE) {
+ *err_str = "Object type mismatch: object path points to a curve!";
+ return NULL;
+ }
+
+ return read_curves_sample(ob, iobject, time);
+ }
+
+ *err_str = "Unsupported object type: verify object path"; // or poke developer
+ return NULL;
+}
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 983f3ce22b8..00ea323f934 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -37,6 +37,7 @@ struct Main;
struct AnimData;
struct KeyingSet;
struct KS_Path;
+struct PathResolvedRNA;
struct bContext;
struct PointerRNA;
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 618b36c5851..483fefbd89c 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -28,7 +28,7 @@
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 277
-#define BLENDER_SUBVERSION 1
+#define BLENDER_SUBVERSION 3
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 6
diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h
new file mode 100644
index 00000000000..51b161f1a06
--- /dev/null
+++ b/source/blender/blenkernel/BKE_cachefile.h
@@ -0,0 +1,67 @@
+/*
+ * ***** 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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_CACHEFILE_H__
+#define __BKE_CACHEFILE_H__
+
+/** \file BKE_cachefile.h
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct CacheFile;
+struct Main;
+struct Scene;
+
+void *BKE_cachefile_add(struct Main *bmain, const char *name);
+
+void BKE_cachefile_init(struct CacheFile *cache_file);
+
+void BKE_cachefile_free(struct CacheFile *cache_file);
+
+struct CacheFile *BKE_cachefile_copy(struct Main *bmain, struct CacheFile *cache_file);
+
+void BKE_cachefile_make_local(struct Main *bmain, struct CacheFile *cache_file, const bool lib_local);
+
+void BKE_cachefile_reload(const struct Main *bmain, struct CacheFile *cache_file);
+
+void BKE_cachefile_ensure_handle(const struct Main *bmain, struct CacheFile *cache_file);
+
+void BKE_cachefile_update_frame(struct Main *bmain, struct Scene *scene, float ctime, const float fps);
+
+bool BKE_cachefile_filepath_get(
+ const struct Main *bmain, const struct CacheFile *cache_file, float frame,
+ char r_filename[1024]);
+
+float BKE_cachefile_time_offset(struct CacheFile *cache_file, const float time, const float fps);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_CACHEFILE_H__ */
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 50fcbd8e139..36330242f18 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -171,6 +171,7 @@ typedef enum {
CLOTH_SIMSETTINGS_FLAG_CCACHE_EDIT = (1 << 12), /* edit cache in editmode */
CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS = (1 << 13), /* don't allow spring compression */
CLOTH_SIMSETTINGS_FLAG_SEW = (1 << 14), /* pull ends of loose edges together */
+ CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH = (1 << 15), /* make simulation respect deformations in the base object */
} CLOTH_SIMSETTINGS_FLAGS;
/* COLLISION FLAGS */
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index e5d348031e9..5b4f5910821 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -61,7 +61,7 @@ void curvemap_reset(struct CurveMap *cuma, const struct rctf
void curvemap_remove(struct CurveMap *cuma, const short flag);
bool curvemap_remove_point(struct CurveMap *cuma, struct CurveMapPoint *cmp);
struct CurveMapPoint *curvemap_insert(struct CurveMap *cuma, float x, float y);
-void curvemap_sethandle(struct CurveMap *cuma, int type);
+void curvemap_handle_set(struct CurveMap *cuma, int type);
void curvemapping_changed(struct CurveMapping *cumap, const bool rem_doubles);
void curvemapping_changed_all(struct CurveMapping *cumap);
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 65a68a4387c..4da6a61cbfa 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -39,6 +39,7 @@ extern "C" {
struct ARegion;
struct bScreen;
+struct CacheFile;
struct ListBase;
struct Main;
struct Object;
@@ -58,6 +59,9 @@ struct bPoseChannel;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
+struct bGPDpalette;
+struct bGPDpalettecolor;
+struct bGPDbrush;
struct wmWindow;
struct wmWindowManager;
struct SpaceText;
@@ -268,6 +272,8 @@ struct Text *CTX_data_edit_text(const bContext *C);
struct MovieClip *CTX_data_edit_movieclip(const bContext *C);
struct Mask *CTX_data_edit_mask(const bContext *C);
+struct CacheFile *CTX_data_edit_cachefile(const bContext *C);
+
int CTX_data_selected_nodes(const bContext *C, ListBase *list);
struct EditBone *CTX_data_active_bone(const bContext *C);
@@ -283,6 +289,9 @@ 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);
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_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index bb4eb652ae2..3a45097efc5 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -48,6 +48,7 @@ struct AnimData;
struct bAction;
struct BezTriple;
struct StructRNA;
+struct PathResolvedRNA;
struct PointerRNA;
struct PropertyRNA;
@@ -107,7 +108,7 @@ bool driver_get_variable_property(
struct ChannelDriver *driver, struct DriverTarget *dtar,
struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index);
-float evaluate_driver(struct ChannelDriver *driver, const float evaltime);
+float evaluate_driver(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime);
/* ************** F-Curve Modifiers *************** */
@@ -278,8 +279,9 @@ void correct_bezpart(float v1[2], float v2[2], float v3[2], float v4[2]);
/* evaluate fcurve */
float evaluate_fcurve(struct FCurve *fcu, float evaltime);
+float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime);
/* evaluate fcurve and store value */
-float calculate_fcurve(struct FCurve *fcu, float evaltime);
+float calculate_fcurve(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime);
/* ************* F-Curve Samples API ******************** */
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index e9e3cd3b16e..ab8b83f8271 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -31,38 +31,53 @@
* \author Joshua Leung
*/
+struct ToolSettings;
struct ListBase;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
+struct bGPDpalette;
+struct bGPDpalettecolor;
struct Main;
/* ------------ Grease-Pencil API ------------------ */
-bool free_gpencil_strokes(struct bGPDframe *gpf);
-void free_gpencil_frames(struct bGPDlayer *gpl);
-void free_gpencil_layers(struct ListBase *list);
-void BKE_gpencil_free(struct bGPdata *gpd);
+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);
-void gpencil_stroke_sync_selection(struct bGPDstroke *gps);
+void BKE_gpencil_stroke_sync_selection(struct bGPDstroke *gps);
-struct bGPDframe *gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
-struct bGPDframe *gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
-struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive);
-struct bGPdata *gpencil_data_addnew(const char name[]);
+struct bGPDframe *BKE_gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
+struct bGPDframe *BKE_gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
+struct bGPDlayer *BKE_gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive);
+struct bGPdata *BKE_gpencil_data_addnew(const char name[]);
-struct bGPDframe *gpencil_frame_duplicate(struct bGPDframe *src);
-struct bGPDlayer *gpencil_layer_duplicate(struct bGPDlayer *src);
-struct bGPdata *gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy);
+struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
+struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
+struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy);
void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local);
-void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
+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);
+
+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);
/* Stroke and Fill - Alpha Visibility Threshold */
#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
+#define GPENCIL_STRENGTH_MIN 0.003f
bool gpencil_layer_is_editable(const struct bGPDlayer *gpl);
@@ -79,12 +94,28 @@ typedef enum eGP_GetFrame_Mode {
GP_GETFRAME_ADD_COPY = 2
} eGP_GetFrame_Mode;
-struct bGPDframe *gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew);
+struct bGPDframe *BKE_gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew);
struct bGPDframe *BKE_gpencil_layer_find_frame(struct bGPDlayer *gpl, int cframe);
-bool gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf);
-
-struct bGPDlayer *gpencil_layer_getactive(struct bGPdata *gpd);
-void gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
-void gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
+bool BKE_gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf);
+
+struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd);
+void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
+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 *palette);
+
+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);
#endif /* __BKE_GPENCIL_H__ */
diff --git a/source/blender/blenkernel/BKE_idcode.h b/source/blender/blenkernel/BKE_idcode.h
index 6de0efe2709..964a49435f1 100644
--- a/source/blender/blenkernel/BKE_idcode.h
+++ b/source/blender/blenkernel/BKE_idcode.h
@@ -42,6 +42,8 @@ bool BKE_idcode_is_valid(short idcode);
int BKE_idcode_to_idfilter(const short idcode);
short BKE_idcode_from_idfilter(const int idfilter);
+int BKE_idcode_to_index(const short idcode);
+
/**
* Return an ID code and steps the index forward 1.
*
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 2ac7e3c97fb..e49019fcfae 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -86,6 +86,7 @@ bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, s
bool id_copy(struct Main *bmain, struct ID *id, struct ID **newid, bool test);
void id_sort_by_name(struct ListBase *lb, struct ID *id);
void BKE_id_expand_local(struct ID *id);
+void BKE_id_copy_ensure_local(struct Main *bmain, struct ID *old_id, struct ID *new_id);
bool new_id(struct ListBase *lb, struct ID *id, const char *name);
void id_clear_lib_data(struct Main *bmain, struct ID *id);
@@ -93,7 +94,7 @@ void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, const bool id_in_ma
struct ListBase *which_libbase(struct Main *mainlib, short type);
-#define MAX_LIBARRAY 34
+#define MAX_LIBARRAY 35
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
/* Main API */
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 44e4da4e0a3..a4f5c425282 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -42,6 +42,8 @@
*/
#include "DNA_listBase.h"
+#include "BKE_library.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -102,8 +104,9 @@ typedef struct Main {
ListBase movieclip;
ListBase mask;
ListBase linestyle;
+ ListBase cachefiles;
- char id_tag_update[256];
+ char id_tag_update[MAX_LIBARRAY];
/* Evaluation context used by viewport */
struct EvaluationContext *eval_ctx;
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index 3d963ac109c..3237c146bc5 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -41,6 +41,9 @@ struct MovieDistortion;
void BKE_movieclip_free(struct MovieClip *clip);
+struct MovieClip *BKE_movieclip_copy(struct Main *bmain, struct MovieClip *clip);
+void BKE_movieclip_make_local(struct Main *bmain, struct MovieClip *clip, const bool lib_local);
+
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain, const char *name, bool *r_exists);
struct MovieClip *BKE_movieclip_file_add_exists(struct Main *bmain, const char *name);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index bf1cfb263eb..0a3cc950f32 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -99,6 +99,8 @@ void BKE_paint_set_overlay_override(enum OverlayFlags flag);
/* palettes */
void BKE_palette_free(struct Palette *palette);
struct Palette *BKE_palette_add(struct Main *bmain, const char *name);
+struct Palette *BKE_palette_copy(struct Main *bmain, struct Palette *palette);
+void BKE_palette_make_local(struct Main *bmain, struct Palette *palette, const bool lib_local);
struct PaletteColor *BKE_palette_color_add(struct Palette *palette);
bool BKE_palette_is_empty(const struct Palette *palette);
void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color);
@@ -107,6 +109,8 @@ void BKE_palette_clear(struct Palette *palette);
/* paint curves */
struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name);
void BKE_paint_curve_free(struct PaintCurve *pc);
+struct PaintCurve *BKE_paint_curve_copy(struct Main *bmain, struct PaintCurve *pc);
+void BKE_paint_curve_make_local(struct Main *bmain, struct PaintCurve *pc, const bool lib_local);
void BKE_paint_init(struct Scene *sce, PaintMode mode, const char col[3]);
void BKE_paint_free(struct Paint *p);
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index ace30b38b3d..42eaba6f2fb 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -64,6 +64,8 @@ struct BVHTreeRayHit;
struct EdgeHash;
struct EffectorContext;
+#define PARTICLE_COLLISION_MAX_COLLISIONS 10
+
#define PARTICLE_P ParticleData * pa; int p
#define LOOP_PARTICLES for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++)
#define LOOP_EXISTING_PARTICLES for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) if (!(pa->flag & PARS_UNEXIST))
@@ -206,8 +208,7 @@ typedef struct ParticleCollisionElement {
typedef struct ParticleCollision {
struct Object *current;
struct Object *hit;
- struct Object *prev;
- struct Object *skip;
+ struct Object *skip[PARTICLE_COLLISION_MAX_COLLISIONS+1];
struct Object *emitter;
struct CollisionModifierData *md; // collision modifier for current object;
@@ -219,7 +220,7 @@ typedef struct ParticleCollision {
float original_ray_length; //original length of co2-co1, needed for collision time evaluation
- int prev_index;
+ int skip_count;
ParticleCollisionElement pce;
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 30bb6954019..811e9136fc9 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -477,4 +477,6 @@ struct ImBuf *BKE_sequencer_render_mask_input(
int cfra, int fra_offset, bool make_float);
void BKE_sequencer_color_balance_apply(struct StripColorBalance *cb, struct ImBuf *ibuf, float mul, bool make_float, struct ImBuf *mask_input);
+void BKE_sequencer_all_free_anim_ibufs(int cfra);
+
#endif /* __BKE_SEQUENCER_H__ */
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 2ca88425c29..1938bb08395 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -52,6 +52,7 @@ struct rcti;
/* **** Common functions **** */
void BKE_tracking_free(struct MovieTracking *tracking);
+void BKE_tracking_copy(struct MovieTracking *tracking_dst, struct MovieTracking *tracking_src);
void BKE_tracking_settings_init(struct MovieTracking *tracking);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 51eeb79c414..ae952faf8a4 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -82,6 +82,7 @@ set(SRC
intern/brush.c
intern/bullet.c
intern/bvhutils.c
+ intern/cachefile.c
intern/camera.c
intern/cdderivedmesh.c
intern/cloth.c
@@ -208,6 +209,7 @@ set(SRC
BKE_brush.h
BKE_bullet.h
BKE_bvhutils.h
+ BKE_cachefile.h
BKE_camera.h
BKE_ccg.h
BKE_cdderivedmesh.h
@@ -501,6 +503,13 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
+if(WITH_ALEMBIC)
+ list(APPEND INC
+ ../alembic
+ )
+ add_definitions(-DWITH_ALEMBIC)
+endif()
+
if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
list(APPEND INC_SYS
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 8f82610a8bb..470098f8c7c 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -156,10 +156,7 @@ bAction *BKE_action_copy(Main *bmain, bAction *src)
}
}
- if (ID_IS_LINKED_DATABLOCK(src)) {
- BKE_id_expand_local(&dst->id);
- BKE_id_lib_local_paths(bmain, src->id.lib, &dst->id);
- }
+ BKE_id_copy_ensure_local(bmain, &src->id, &dst->id);
return dst;
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index d04b950c043..1a5d77bbc07 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -97,6 +97,7 @@ bool id_type_can_have_animdata(const short id_type)
case ID_MC:
case ID_MSK:
case ID_GD:
+ case ID_CF:
return true;
/* no AnimData */
@@ -1160,6 +1161,9 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u
/* grease pencil */
ANIMDATA_IDS_CB(mainptr->gpencil.first);
+
+ /* cache files */
+ ANIMDATA_IDS_CB(mainptr->cachefiles.first);
}
/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
@@ -1250,6 +1254,9 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const cha
/* grease pencil */
RENAMEFIX_ANIM_IDS(mainptr->gpencil.first);
+
+ /* cache files */
+ RENAMEFIX_ANIM_IDS(mainptr->cachefiles.first);
/* scenes */
RENAMEFIX_ANIM_NODETREE_IDS(mainptr->scene.first, Scene);
@@ -1482,161 +1489,193 @@ static bool animsys_remap_path(AnimMapper *UNUSED(remap), char *path, char **dst
return false;
}
+static bool animsys_store_rna_setting(
+ PointerRNA *ptr, AnimMapper *remap,
+ /* typically 'fcu->rna_path', 'fcu->array_index' */
+ const char *rna_path, const int array_index,
+ PathResolvedRNA *r_result)
+{
+ bool success = false;
+
+ char *path = NULL;
+ bool free_path;
+
+ /* get path, remapped as appropriate to work in its new environment */
+ free_path = animsys_remap_path(remap, (char *)rna_path, &path);
+
+ /* write value to setting */
+ if (path) {
+ /* get property to write to */
+ if (RNA_path_resolve_property(ptr, path, &r_result->ptr, &r_result->prop)) {
+ if ((ptr->id.data == NULL) || RNA_property_animateable(&r_result->ptr, r_result->prop)) {
+ int array_len = RNA_property_array_length(&r_result->ptr, r_result->prop);
+
+ if (array_len && array_index >= array_len) {
+ if (G.debug & G_DEBUG) {
+ printf("Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d\n",
+ (ptr && ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
+ path, array_index, array_len - 1);
+ }
+ }
+ else {
+ r_result->prop_index = array_len ? array_index : -1;
+ success = true;
+ }
+ }
+ }
+ else {
+ /* failed to get path */
+ /* XXX don't tag as failed yet though, as there are some legit situations (Action Constraint)
+ * where some channels will not exist, but shouldn't lock up Action */
+ if (G.debug & G_DEBUG) {
+ printf("Animato: Invalid path. ID = '%s', '%s[%d]'\n",
+ (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
+ path, array_index);
+ }
+ }
+ }
+
+ /* free temp path-info */
+ if (free_path) {
+ MEM_freeN((void *)path);
+ }
+
+ return success;
+}
+
/* less than 1.0 evaluates to false, use epsilon to avoid float error */
#define ANIMSYS_FLOAT_AS_BOOL(value) ((value) > ((1.0f - FLT_EPSILON)))
/* Write the given value to a setting using RNA, and return success */
-static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_index, float value)
+static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float value)
{
- PropertyRNA *prop;
- PointerRNA new_ptr;
+ PropertyRNA *prop = anim_rna->prop;
+ PointerRNA *ptr = &anim_rna->ptr;
+ int array_index = anim_rna->prop_index;
- //printf("%p %s %i %f\n", ptr, path, array_index, value);
-
- /* get property to write to */
- if (RNA_path_resolve_property(ptr, path, &new_ptr, &prop)) {
- /* set value for animatable numerical values only
- * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated
- * without an ID provided, which causes the animateable test to fail!
- */
- if (RNA_property_animateable(&new_ptr, prop) || (ptr->id.data == NULL)) {
- int array_len = RNA_property_array_length(&new_ptr, prop);
- bool written = false;
-
- if (array_len && array_index >= array_len) {
- if (G.debug & G_DEBUG) {
- printf("Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d\n",
- (ptr && ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
- path, array_index, array_len - 1);
+ /* caller must ensure this is animatable */
+ BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL);
+
+ /* set value for animatable numerical values only
+ * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated
+ * without an ID provided, which causes the animateable test to fail!
+ */
+ bool written = false;
+
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ {
+ const int value_coerce = ANIMSYS_FLOAT_AS_BOOL(value);
+ if (array_index != -1) {
+ if (RNA_property_boolean_get_index(ptr, prop, array_index) != value_coerce) {
+ RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce);
+ written = true;
}
-
- return false;
}
-
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- if (array_len) {
- if (RNA_property_boolean_get_index(&new_ptr, prop, array_index) != ANIMSYS_FLOAT_AS_BOOL(value)) {
- RNA_property_boolean_set_index(&new_ptr, prop, array_index, ANIMSYS_FLOAT_AS_BOOL(value));
- written = true;
- }
- }
- else {
- if (RNA_property_boolean_get(&new_ptr, prop) != ANIMSYS_FLOAT_AS_BOOL(value)) {
- RNA_property_boolean_set(&new_ptr, prop, ANIMSYS_FLOAT_AS_BOOL(value));
- written = true;
- }
- }
- break;
- case PROP_INT:
- if (array_len) {
- if (RNA_property_int_get_index(&new_ptr, prop, array_index) != (int)value) {
- RNA_property_int_set_index(&new_ptr, prop, array_index, (int)value);
- written = true;
- }
- }
- else {
- if (RNA_property_int_get(&new_ptr, prop) != (int)value) {
- RNA_property_int_set(&new_ptr, prop, (int)value);
- written = true;
- }
- }
- break;
- case PROP_FLOAT:
- if (array_len) {
- if (RNA_property_float_get_index(&new_ptr, prop, array_index) != value) {
- RNA_property_float_set_index(&new_ptr, prop, array_index, value);
- written = true;
- }
- }
- else {
- if (RNA_property_float_get(&new_ptr, prop) != value) {
- RNA_property_float_set(&new_ptr, prop, value);
- written = true;
- }
- }
- break;
- case PROP_ENUM:
- if (RNA_property_enum_get(&new_ptr, prop) != (int)value) {
- RNA_property_enum_set(&new_ptr, prop, (int)value);
- written = true;
- }
- break;
- default:
- /* nothing can be done here... so it is unsuccessful? */
- return false;
+ else {
+ if (RNA_property_boolean_get(ptr, prop) != value_coerce) {
+ RNA_property_boolean_set(ptr, prop, value_coerce);
+ written = true;
+ }
}
-
- /* RNA property update disabled for now - [#28525] [#28690] [#28774] [#28777] */
-#if 0
- /* buffer property update for later flushing */
- if (written && RNA_property_update_check(prop)) {
- short skip_updates_hack = 0;
-
- /* optimization hacks: skip property updates for those properties
- * for we know that which the updates in RNA were really just for
- * flushing property editing via UI/Py
- */
- if (new_ptr.type == &RNA_PoseBone) {
- /* bone transforms - update pose (i.e. tag depsgraph) */
- skip_updates_hack = 1;
+ break;
+ }
+ case PROP_INT:
+ {
+ const int value_coerce = (int)value;
+ if (array_index != -1) {
+ if (RNA_property_int_get_index(ptr, prop, array_index) != value_coerce) {
+ RNA_property_int_set_index(ptr, prop, array_index, value_coerce);
+ written = true;
}
-
- if (skip_updates_hack == 0)
- RNA_property_update_cache_add(&new_ptr, prop);
}
-#endif
-
- /* as long as we don't do property update, we still tag datablock
- * as having been updated. this flag does not cause any updates to
- * be run, it's for e.g. render engines to synchronize data */
- if (written && new_ptr.id.data) {
- ID *id = new_ptr.id.data;
-
- /* for cases like duplifarmes it's only a temporary so don't
- * notify anyone of updates */
- if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) {
- id->tag |= LIB_TAG_ID_RECALC;
- DAG_id_type_tag(G.main, GS(id->name));
+ else {
+ if (RNA_property_int_get(ptr, prop) != value_coerce) {
+ RNA_property_int_set(ptr, prop, value_coerce);
+ written = true;
}
}
+ break;
}
-
- /* successful */
- return true;
+ case PROP_FLOAT:
+ {
+ if (array_index != -1) {
+ if (RNA_property_float_get_index(ptr, prop, array_index) != value) {
+ RNA_property_float_set_index(ptr, prop, array_index, value);
+ written = true;
+ }
+ }
+ else {
+ if (RNA_property_float_get(ptr, prop) != value) {
+ RNA_property_float_set(ptr, prop, value);
+ written = true;
+ }
+ }
+ break;
+ }
+ case PROP_ENUM:
+ {
+ const int value_coerce = (int)value;
+ if (RNA_property_enum_get(ptr, prop) != value_coerce) {
+ RNA_property_enum_set(ptr, prop, value_coerce);
+ written = true;
+ }
+ break;
+ }
+ default:
+ /* nothing can be done here... so it is unsuccessful? */
+ return false;
}
- else {
- /* failed to get path */
- /* XXX don't tag as failed yet though, as there are some legit situations (Action Constraint)
- * where some channels will not exist, but shouldn't lock up Action */
- if (G.debug & G_DEBUG) {
- printf("Animato: Invalid path. ID = '%s', '%s[%d]'\n",
- (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
- path, array_index);
+
+ /* RNA property update disabled for now - [#28525] [#28690] [#28774] [#28777] */
+#if 0
+ /* buffer property update for later flushing */
+ if (written && RNA_property_update_check(prop)) {
+ short skip_updates_hack = 0;
+
+ /* optimization hacks: skip property updates for those properties
+ * for we know that which the updates in RNA were really just for
+ * flushing property editing via UI/Py
+ */
+ if (new_ptr.type == &RNA_PoseBone) {
+ /* bone transforms - update pose (i.e. tag depsgraph) */
+ skip_updates_hack = 1;
+ }
+
+ if (skip_updates_hack == 0)
+ RNA_property_update_cache_add(ptr, prop);
+ }
+#endif
+
+ /* as long as we don't do property update, we still tag datablock
+ * as having been updated. this flag does not cause any updates to
+ * be run, it's for e.g. render engines to synchronize data */
+ if (written && ptr->id.data) {
+ ID *id = ptr->id.data;
+
+ /* for cases like duplifarmes it's only a temporary so don't
+ * notify anyone of updates */
+ if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) {
+ id->tag |= LIB_TAG_ID_RECALC;
+ DAG_id_type_tag(G.main, GS(id->name));
}
- return false;
}
+
+ /* successful */
+ return true;
}
/* Simple replacement based data-setting of the FCurve using RNA */
bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu, float curval)
{
- char *path = NULL;
- bool free_path = false;
+ PathResolvedRNA anim_rna;
bool ok = false;
-
- /* get path, remapped as appropriate to work in its new environment */
- free_path = animsys_remap_path(remap, fcu->rna_path, &path);
-
- /* write value to setting */
- if (path)
- ok = animsys_write_rna_setting(ptr, path, fcu->array_index, curval);
-
- /* free temp path-info */
- if (free_path)
- MEM_freeN(path);
-
+
+ if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ ok = animsys_write_rna_setting(&anim_rna, curval);
+ }
+
/* return whether we were successful */
return ok;
}
@@ -1654,8 +1693,11 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper
if ((fcu->grp == NULL) || (fcu->grp->flag & AGRP_MUTED) == 0) {
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
- const float curval = calculate_fcurve(fcu, ctime);
- BKE_animsys_execute_fcurve(ptr, remap, fcu, curval);
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
+ animsys_write_rna_setting(&anim_rna, curval);
+ }
}
}
}
@@ -1684,8 +1726,12 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime
/* evaluate this using values set already in other places
* NOTE: for 'layering' option later on, we should check if we should remove old value before adding
* new to only be done when drivers only changed */
- const float curval = calculate_fcurve(fcu, ctime);
- ok = BKE_animsys_execute_fcurve(ptr, NULL, fcu, curval);
+
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
+ ok = animsys_write_rna_setting(&anim_rna, curval);
+ }
/* clear recalc flag */
driver->flag &= ~DRIVER_FLAG_RECALC;
@@ -1753,8 +1799,11 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
for (fcu = agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu = fcu->next) {
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
- const float curval = calculate_fcurve(fcu, ctime);
- BKE_animsys_execute_fcurve(ptr, remap, fcu, curval);
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
+ animsys_write_rna_setting(&anim_rna, curval);
+ }
}
}
}
@@ -2612,8 +2661,12 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
AnimOverride *aor;
/* for each override, simply execute... */
- for (aor = adt->overrides.first; aor; aor = aor->next)
- animsys_write_rna_setting(ptr, aor->rna_path, aor->array_index, aor->value);
+ for (aor = adt->overrides.first; aor; aor = aor->next) {
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, NULL, aor->rna_path, aor->array_index, &anim_rna)) {
+ animsys_write_rna_setting(&anim_rna, aor->value);
+ }
+ }
}
/* ***************************************** */
@@ -2827,6 +2880,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
/* grease pencil */
EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM);
+
+ /* cache files */
+ EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM);
/* objects */
/* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
@@ -2888,8 +2944,13 @@ void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
* NOTE: for 'layering' option later on, we should check if we should remove old value before adding
* new to only be done when drivers only changed */
//printf("\told val = %f\n", fcu->curval);
- const float curval = calculate_fcurve(fcu, eval_ctx->ctime);
- ok = BKE_animsys_execute_fcurve(&id_ptr, NULL, fcu, curval);
+
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(&id_ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, eval_ctx->ctime);
+ ok = animsys_write_rna_setting(&anim_rna, curval);
+ }
+
//printf("\tnew val = %f\n", fcu->curval);
/* clear recalc flag */
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 790272c4411..c644fe09364 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -194,10 +194,7 @@ bArmature *BKE_armature_copy(Main *bmain, bArmature *arm)
newArm->act_edbone = NULL;
newArm->sketch = NULL;
- if (ID_IS_LINKED_DATABLOCK(arm)) {
- BKE_id_expand_local(&newArm->id);
- BKE_id_lib_local_paths(bmain, arm->id.lib, &newArm->id);
- }
+ BKE_id_copy_ensure_local(bmain, &arm->id, &newArm->id);
return newArm;
}
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index a708c59fa97..487b8ffa2b5 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -48,6 +48,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_brush_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_image_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
@@ -653,6 +654,12 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
rewrite_path_fixed(clip->name, visit_cb, absbase, bpath_user_data);
break;
}
+ case ID_CF:
+ {
+ CacheFile *cache_file = (CacheFile *)id;
+ rewrite_path_fixed(cache_file->filepath, visit_cb, absbase, bpath_user_data);
+ break;
+ }
default:
/* Nothing to do for other IDs that don't contain file paths. */
break;
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 9027287a457..8ef1fae1155 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -197,10 +197,7 @@ Brush *BKE_brush_copy(Main *bmain, Brush *brush)
/* enable fake user by default */
id_fake_user_set(&brush->id);
- if (ID_IS_LINKED_DATABLOCK(brush)) {
- BKE_id_expand_local(&brushn->id);
- BKE_id_lib_local_paths(bmain, brush->id.lib, &brushn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &brush->id, &brushn->id);
return brushn;
}
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
new file mode 100644
index 00000000000..16f263791db
--- /dev/null
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -0,0 +1,173 @@
+/*
+ * ***** 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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/cachefile.c
+ * \ingroup bke
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_cachefile_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_fileops.h"
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_animsys.h"
+#include "BKE_cachefile.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+#ifdef WITH_ALEMBIC
+# include "ABC_alembic.h"
+#endif
+
+void *BKE_cachefile_add(Main *bmain, const char *name)
+{
+ CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name);
+
+ BKE_cachefile_init(cache_file);
+
+ return cache_file;
+}
+
+void BKE_cachefile_init(CacheFile *cache_file)
+{
+ cache_file->handle = NULL;
+ cache_file->filepath[0] = '\0';
+ cache_file->override_frame = false;
+ cache_file->frame = 0.0f;
+ cache_file->is_sequence = false;
+ cache_file->scale = 1.0f;
+}
+
+/** Free (or release) any data used by this cachefile (does not free the cachefile itself). */
+void BKE_cachefile_free(CacheFile *cache_file)
+{
+ BKE_animdata_free((ID *)cache_file, false);
+
+#ifdef WITH_ALEMBIC
+ ABC_free_handle(cache_file->handle);
+#endif
+
+ BLI_freelistN(&cache_file->object_paths);
+}
+
+CacheFile *BKE_cachefile_copy(Main *bmain, CacheFile *cache_file)
+{
+ CacheFile *new_cache_file = BKE_libblock_copy(bmain, &cache_file->id);
+ new_cache_file->handle = NULL;
+
+ BLI_listbase_clear(&cache_file->object_paths);
+
+ BKE_id_copy_ensure_local(bmain, &cache_file->id, &new_cache_file->id);
+
+ return new_cache_file;
+}
+
+void BKE_cachefile_make_local(Main *bmain, CacheFile *cache_file, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &cache_file->id, true, lib_local);
+}
+
+void BKE_cachefile_reload(const Main *bmain, CacheFile *cache_file)
+{
+ char filepath[FILE_MAX];
+
+ BLI_strncpy(filepath, cache_file->filepath, sizeof(filepath));
+ BLI_path_abs(filepath, ID_BLEND_PATH(bmain, &cache_file->id));
+
+#ifdef WITH_ALEMBIC
+ if (cache_file->handle) {
+ ABC_free_handle(cache_file->handle);
+ }
+
+ cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths);
+#endif
+}
+
+void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
+{
+ if (cache_file->handle == NULL) {
+ BKE_cachefile_reload(bmain, cache_file);
+ }
+}
+
+void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, const float fps)
+{
+ CacheFile *cache_file;
+ char filename[FILE_MAX];
+
+ for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
+ /* Execute drivers only, as animation has already been done. */
+ BKE_animsys_evaluate_animdata(scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
+
+ if (!cache_file->is_sequence) {
+ continue;
+ }
+
+ const float time = BKE_cachefile_time_offset(cache_file, ctime, fps);
+
+ if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) {
+#ifdef WITH_ALEMBIC
+ ABC_free_handle(cache_file->handle);
+ cache_file->handle = ABC_create_handle(filename, NULL);
+#endif
+ }
+ }
+}
+
+bool BKE_cachefile_filepath_get(
+ const Main *bmain, const CacheFile *cache_file, float frame,
+ char r_filepath[FILE_MAX])
+{
+ BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX);
+ BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id));
+
+ int fframe;
+ int frame_len;
+
+ if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) {
+ char ext[32];
+ BLI_path_frame_strip(r_filepath, true, ext);
+ BLI_path_frame(r_filepath, frame, frame_len);
+ BLI_ensure_extension(r_filepath, FILE_MAX, ext);
+
+ /* TODO(kevin): store sequence range? */
+ return BLI_exists(r_filepath);
+ }
+
+ return true;
+}
+
+float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const float fps)
+{
+ const float frame = (cache_file->override_frame ? cache_file->frame : time);
+ return cache_file->is_sequence ? frame : frame / fps;
+}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 4229b2a727e..85ce399b770 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -99,10 +99,7 @@ Camera *BKE_camera_copy(Main *bmain, Camera *cam)
camn = BKE_libblock_copy(bmain, &cam->id);
- if (ID_IS_LINKED_DATABLOCK(cam)) {
- BKE_id_expand_local(&camn->id);
- BKE_id_lib_local_paths(bmain, cam->id.lib, &camn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &cam->id, &camn->id);
return camn;
}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 159d5b82a6c..d257a1cfcae 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -3402,7 +3402,7 @@ void CDDM_calc_edges(DerivedMesh *dm)
BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2);
j = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
- if (j == 0) {
+ if (j == 0 || !eindex) {
med->flag = ME_EDGEDRAW | ME_EDGERENDER;
*index = ORIGINDEX_NONE;
}
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index b979f892e86..329060644b9 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -58,6 +58,7 @@ static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*verte
static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm );
static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first);
static void cloth_update_springs( ClothModifierData *clmd );
+static void cloth_update_verts( Object *ob, ClothModifierData *clmd, DerivedMesh *dm );
static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm );
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm );
static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm );
@@ -96,6 +97,7 @@ void cloth_init(ClothModifierData *clmd )
clmd->sim_parms->avg_spring_len = 0.0;
clmd->sim_parms->presets = 2; /* cotton as start setting */
clmd->sim_parms->timescale = 1.0f; /* speed factor, describes how fast cloth moves */
+ clmd->sim_parms->time_scale = 1.0f; /* multiplies cloth speed */
clmd->sim_parms->reset = 0;
clmd->sim_parms->vel_damping = 1.0f; /* 1.0 = no damping, 0.0 = fully dampened */
@@ -368,10 +370,13 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
effectors = pdInitEffectors(clmd->scene, ob, NULL, clmd->sim_parms->effector_weights, true);
+ if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH )
+ cloth_update_verts ( ob, clmd, result );
+
/* Support for dynamic vertex groups, changing from frame to frame */
cloth_apply_vgroup ( clmd, result );
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW )
+ if ( clmd->sim_parms->flags & (CLOTH_SIMSETTINGS_FLAG_SEW | CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) )
cloth_update_spring_lengths ( clmd, result );
cloth_update_springs( clmd );
@@ -407,7 +412,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
BKE_ptcache_id_from_cloth(&pid, ob, clmd);
BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
- clmd->sim_parms->timescale= timescale;
+ clmd->sim_parms->timescale= timescale * clmd->sim_parms->time_scale;
if (clmd->sim_parms->reset || (clmd->clothObject && dm->getNumVerts(dm) != clmd->clothObject->mvert_num)) {
clmd->sim_parms->reset = 0;
@@ -804,7 +809,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
clmd->clothObject->springs = NULL;
clmd->clothObject->numsprings = -1;
- if ( clmd->sim_parms->shapekey_rest )
+ if ( clmd->sim_parms->shapekey_rest && !(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH ) )
shapekey_rest = dm->getVertDataArray ( dm, CD_CLOTH_ORCO );
mvert = dm->getVertArray (dm);
@@ -1180,6 +1185,20 @@ static void cloth_update_springs( ClothModifierData *clmd )
cloth_hair_update_bending_targets(clmd);
}
+/* Update rest verts, for dynamically deformable cloth */
+static void cloth_update_verts( Object *ob, ClothModifierData *clmd, DerivedMesh *dm )
+{
+ unsigned int i = 0;
+ MVert *mvert = dm->getVertArray (dm);
+ ClothVertex *verts = clmd->clothObject->verts;
+
+ /* vertex count is already ensured to match */
+ for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) {
+ copy_v3_v3(verts->xrest, mvert[i].co);
+ mul_m4_v3(ob->obmat, verts->xrest);
+ }
+}
+
/* Update spring rest lenght, for dynamically deformable cloth */
static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm )
{
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 53a74024c51..4f3ffed41bc 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -293,8 +293,8 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
cuma->curve[1].x = clipr->xmax;
cuma->curve[1].y = clipr->ymin;
if (slope == CURVEMAP_SLOPE_POS_NEG) {
- cuma->curve[0].flag |= CUMA_VECTOR;
- cuma->curve[1].flag |= CUMA_VECTOR;
+ cuma->curve[0].flag |= CUMA_HANDLE_VECTOR;
+ cuma->curve[1].flag |= CUMA_HANDLE_VECTOR;
}
break;
case CURVE_PRESET_SHARP:
@@ -391,15 +391,25 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
}
}
-/* if type==1: vector, else auto */
-void curvemap_sethandle(CurveMap *cuma, int type)
+/**
+ * \param type: eBezTriple_Handle
+ */
+void curvemap_handle_set(CurveMap *cuma, int type)
{
int a;
for (a = 0; a < cuma->totpoint; a++) {
if (cuma->curve[a].flag & CUMA_SELECT) {
- if (type) cuma->curve[a].flag |= CUMA_VECTOR;
- else cuma->curve[a].flag &= ~CUMA_VECTOR;
+ cuma->curve[a].flag &= ~(CUMA_HANDLE_VECTOR | CUMA_HANDLE_AUTO_ANIM);
+ if (type == HD_VECT) {
+ cuma->curve[a].flag |= CUMA_HANDLE_VECTOR;
+ }
+ else if (type == HD_AUTO_ANIM) {
+ cuma->curve[a].flag |= CUMA_HANDLE_AUTO_ANIM;
+ }
+ else {
+ /* pass */
+ }
}
}
}
@@ -457,7 +467,7 @@ static void calchandle_curvemap(
if (len_a == 0.0f) len_a = 1.0f;
if (len_b == 0.0f) len_b = 1.0f;
- if (bezt->h1 == HD_AUTO || bezt->h2 == HD_AUTO) { /* auto */
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */
float tvec[2];
tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;
@@ -465,13 +475,57 @@ static void calchandle_curvemap(
len = len_v2(tvec) * 2.5614f;
if (len != 0.0f) {
- if (bezt->h1 == HD_AUTO) {
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
len_a /= len;
madd_v2_v2v2fl(p2_h1, p2, tvec, -len_a);
+
+ if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
+ const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
+ const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
+ if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) ||
+ (ydiff1 >= 0.0f && ydiff2 >= 0.0f))
+ {
+ bezt->vec[0][1] = bezt->vec[1][1];
+ }
+ else { /* handles should not be beyond y coord of two others */
+ if (ydiff1 <= 0.0f) {
+ if (prev->vec[1][1] > bezt->vec[0][1]) {
+ bezt->vec[0][1] = prev->vec[1][1];
+ }
+ }
+ else {
+ if (prev->vec[1][1] < bezt->vec[0][1]) {
+ bezt->vec[0][1] = prev->vec[1][1];
+ }
+ }
+ }
+ }
}
- if (bezt->h2 == HD_AUTO) {
+ if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
len_b /= len;
madd_v2_v2v2fl(p2_h2, p2, tvec, len_b);
+
+ if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
+ const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
+ const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
+ if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f)||
+ (ydiff1 >= 0.0f && ydiff2 >= 0.0f))
+ {
+ bezt->vec[2][1] = bezt->vec[1][1];
+ }
+ else { /* handles should not be beyond y coord of two others */
+ if (ydiff1 <= 0.0f) {
+ if (next->vec[1][1] < bezt->vec[2][1]) {
+ bezt->vec[2][1] = next->vec[1][1];
+ }
+ }
+ else {
+ if (next->vec[1][1] > bezt->vec[2][1]) {
+ bezt->vec[2][1] = next->vec[1][1];
+ }
+ }
+ }
+ }
}
}
}
@@ -540,10 +594,15 @@ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr)
cuma->maxtable = max_ff(cuma->maxtable, cmp[a].x);
bezt[a].vec[1][0] = cmp[a].x;
bezt[a].vec[1][1] = cmp[a].y;
- if (cmp[a].flag & CUMA_VECTOR)
+ if (cmp[a].flag & CUMA_HANDLE_VECTOR) {
bezt[a].h1 = bezt[a].h2 = HD_VECT;
- else
+ }
+ else if (cmp[a].flag & CUMA_HANDLE_AUTO_ANIM) {
+ bezt[a].h1 = bezt[a].h2 = HD_AUTO_ANIM;
+ }
+ else {
bezt[a].h1 = bezt[a].h2 = HD_AUTO;
+ }
}
const BezTriple *bezt_prev = NULL;
@@ -773,12 +832,12 @@ void curvemapping_changed(CurveMapping *cumap, const bool rem_doubles)
dy = cmp[a].y - cmp[a + 1].y;
if (sqrtf(dx * dx + dy * dy) < thresh) {
if (a == 0) {
- cmp[a + 1].flag |= CUMA_VECTOR;
+ cmp[a + 1].flag |= CUMA_HANDLE_VECTOR;
if (cmp[a + 1].flag & CUMA_SELECT)
cmp[a].flag |= CUMA_SELECT;
}
else {
- cmp[a].flag |= CUMA_VECTOR;
+ cmp[a].flag |= CUMA_HANDLE_VECTOR;
if (cmp[a].flag & CUMA_SELECT)
cmp[a + 1].flag |= CUMA_SELECT;
}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 4c9ddd495e3..70fdd4aa72e 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -46,6 +46,7 @@
#include "BLT_translation.h"
#include "DNA_armature_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_constraint_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -63,6 +64,7 @@
#include "BKE_anim.h" /* for the curve calculation part */
#include "BKE_armature.h"
#include "BKE_bvhutils.h"
+#include "BKE_cachefile.h"
#include "BKE_camera.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
@@ -86,6 +88,10 @@
# include "BPY_extern.h"
#endif
+#ifdef WITH_ALEMBIC
+# include "ABC_alembic.h"
+#endif
+
/* ---------------------------------------------------------------------------- */
/* Useful macros for testing various common flag combinations */
@@ -4333,6 +4339,73 @@ static bConstraintTypeInfo CTI_OBJECTSOLVER = {
objectsolver_evaluate /* evaluate */
};
+/* ----------- Transform Cache ------------- */
+
+static void transformcache_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+ bTransformCacheConstraint *data = con->data;
+ func(con, (ID **)&data->cache_file, false, userdata);
+}
+
+static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+#ifdef WITH_ALEMBIC
+ bTransformCacheConstraint *data = con->data;
+ Scene *scene = cob->scene;
+
+ const float frame = BKE_scene_frame_get(scene);
+ const float time = BKE_cachefile_time_offset(data->cache_file, frame, FPS);
+
+ CacheFile *cache_file = data->cache_file;
+
+ BKE_cachefile_ensure_handle(G.main, cache_file);
+
+ ABC_get_transform(cache_file->handle, cob->ob, data->object_path,
+ cob->matrix, time, cache_file->scale);
+#else
+ UNUSED_VARS(con, cob);
+#endif
+
+ UNUSED_VARS(targets);
+}
+
+static void transformcache_copy(bConstraint *con, bConstraint *srccon)
+{
+ bTransformCacheConstraint *src = srccon->data;
+ bTransformCacheConstraint *dst = con->data;
+
+ BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path));
+ dst->cache_file = src->cache_file;
+
+ if (dst->cache_file) {
+ id_us_plus(&dst->cache_file->id);
+ }
+}
+
+static void transformcache_free(bConstraint *con)
+{
+ bTransformCacheConstraint *data = con->data;
+
+ if (data->cache_file) {
+ id_us_min(&data->cache_file->id);
+ }
+}
+
+static bConstraintTypeInfo CTI_TRANSFORM_CACHE = {
+ CONSTRAINT_TYPE_TRANSFORM_CACHE, /* type */
+ sizeof(bTransformCacheConstraint), /* size */
+ "Transform Cache", /* name */
+ "bTransformCacheConstraint", /* struct name */
+ transformcache_free, /* free data */
+ transformcache_id_looper, /* id looper */
+ transformcache_copy, /* copy data */
+ NULL, /* new data */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ NULL, /* get target matrix */
+ transformcache_evaluate /* evaluate */
+};
+
/* ************************* Constraints Type-Info *************************** */
/* All of the constraints api functions use bConstraintTypeInfo structs to carry out
* and operations that involve constraint specific code.
@@ -4374,6 +4447,7 @@ static void constraints_init_typeinfo(void)
constraintsTypeInfo[26] = &CTI_FOLLOWTRACK; /* Follow Track Constraint */
constraintsTypeInfo[27] = &CTI_CAMERASOLVER; /* Camera Solver Constraint */
constraintsTypeInfo[28] = &CTI_OBJECTSOLVER; /* Object Solver Constraint */
+ constraintsTypeInfo[29] = &CTI_TRANSFORM_CACHE; /* Transform Cache Constraint */
}
/* This function should be used for getting the appropriate type-info when only
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 5b7698544e0..926ca8da192 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -1067,6 +1067,11 @@ struct EditBone *CTX_data_active_bone(const bContext *C)
return ctx_data_pointer_get(C, "active_bone");
}
+struct CacheFile *CTX_data_edit_cachefile(const bContext *C)
+{
+ return ctx_data_pointer_get(C, "edit_cachefile");
+}
+
int CTX_data_selected_bones(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selected_bones", list);
@@ -1112,6 +1117,21 @@ 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)
+{
+ return ctx_data_pointer_get(C, "active_gpencil_brush");
+}
+
bGPDframe *CTX_data_active_gpencil_frame(const bContext *C)
{
return ctx_data_pointer_get(C, "active_gpencil_frame");
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 07f4e4f1610..90a514781d7 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -207,10 +207,7 @@ Curve *BKE_curve_copy(Main *bmain, Curve *cu)
id_us_plus((ID *)cun->vfonti);
id_us_plus((ID *)cun->vfontbi);
- if (ID_IS_LINKED_DATABLOCK(cu)) {
- BKE_id_expand_local(&cun->id);
- BKE_id_lib_local_paths(bmain, cu->id.lib, &cun->id);
- }
+ BKE_id_copy_ensure_local(bmain, &cu->id, &cun->id);
return cun;
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 7a3071227e6..85dd39698de 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -46,6 +46,7 @@
#include "DNA_anim_types.h"
#include "DNA_camera_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_lattice_types.h"
@@ -66,6 +67,7 @@
#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
+#include "BKE_idcode.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
@@ -2175,7 +2177,12 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob)
if (cti) {
/* special case for camera tracking -- it doesn't use targets to define relations */
- if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) {
+ if (ELEM(cti->type,
+ CONSTRAINT_TYPE_FOLLOWTRACK,
+ CONSTRAINT_TYPE_CAMERASOLVER,
+ CONSTRAINT_TYPE_OBJECTSOLVER,
+ CONSTRAINT_TYPE_TRANSFORM_CACHE))
+ {
ob->recalc |= OB_RECALC_OB;
}
else if (cti->get_constraint_targets) {
@@ -2806,9 +2813,7 @@ void DAG_ids_flush_tagged(Main *bmain)
ListBase *lb = lbarray[a];
ID *id = lb->first;
- /* we tag based on first ID type character to avoid
- * looping over all ID's in case there are no tags */
- if (id && bmain->id_tag_update[id->name[0]]) {
+ if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
for (; id; id = id->next) {
if (id->tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)) {
@@ -2848,9 +2853,7 @@ void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
ListBase *lb = lbarray[a];
ID *id = lb->first;
- /* we tag based on first ID type character to avoid
- * looping over all ID's in case there are no tags */
- if (id && bmain->id_tag_update[id->name[0]]) {
+ if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
updated = true;
break;
}
@@ -2931,9 +2934,7 @@ void DAG_ids_clear_recalc(Main *bmain)
ListBase *lb = lbarray[a];
ID *id = lb->first;
- /* we tag based on first ID type character to avoid
- * looping over all ID's in case there are no tags */
- if (id && bmain->id_tag_update[id->name[0]]) {
+ if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
for (; id; id = id->next) {
if (id->tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA))
id->tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
@@ -3008,6 +3009,33 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
/* BLI_assert(!"invalid flag for this 'idtype'"); */
}
}
+ else if (GS(id->name) == ID_CF) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
+
+ if (md) {
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+
+ if (mcmd->cache_file && (&mcmd->cache_file->id == id)) {
+ ob->recalc |= OB_RECALC_DATA;
+ continue;
+ }
+ }
+
+ for (bConstraint *con = ob->constraints.first; con; con = con->next) {
+ if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
+ continue;
+ }
+
+ bTransformCacheConstraint *data = con->data;
+
+ if (data->cache_file && (&data->cache_file->id == id)) {
+ ob->recalc |= OB_RECALC_DATA;
+ break;
+ }
+ }
+ }
+ }
}
void DAG_id_tag_update(ID *id, short flag)
@@ -3027,12 +3055,12 @@ void DAG_id_type_tag(Main *bmain, short idtype)
DAG_id_type_tag(bmain, ID_SCE);
}
- bmain->id_tag_update[((char *)&idtype)[0]] = 1;
+ bmain->id_tag_update[BKE_idcode_to_index(idtype)] = 1;
}
int DAG_id_type_tagged(Main *bmain, short idtype)
{
- return bmain->id_tag_update[((char *)&idtype)[0]];
+ return bmain->id_tag_update[BKE_idcode_to_index(idtype)];
}
#if 0 // UNUSED
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 395161aa6ed..a89d423e7a6 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -1859,7 +1859,7 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
* - "evaltime" is the frame at which F-Curve is being evaluated
* - has to return a float value
*/
-float evaluate_driver(ChannelDriver *driver, const float evaltime)
+float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime)
{
DriverVar *dvar;
@@ -1944,7 +1944,9 @@ float evaluate_driver(ChannelDriver *driver, const float evaltime)
* - on errors it reports, then returns 0.0f
*/
BLI_mutex_lock(&python_driver_lock);
- driver->curval = BPY_driver_exec(driver, evaltime);
+
+ driver->curval = BPY_driver_exec(anim_rna, driver, evaltime);
+
BLI_mutex_unlock(&python_driver_lock);
}
#else /* WITH_PYTHON*/
@@ -2599,25 +2601,64 @@ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime)
/* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime")
* Note: this is also used for drivers
*/
-float evaluate_fcurve(FCurve *fcu, float evaltime)
+static float evaluate_fcurve_ex(FCurve *fcu, float evaltime, float cvalue)
{
FModifierStackStorage *storage;
- float cvalue = 0.0f;
float devaltime;
+
+ /* evaluate modifiers which modify time to evaluate the base curve at */
+ storage = evaluate_fmodifiers_storage_new(&fcu->modifiers);
+ devaltime = evaluate_time_fmodifiers(storage, &fcu->modifiers, fcu, cvalue, evaltime);
+
+ /* evaluate curve-data
+ * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying
+ * F-Curve modifier on the stack requested the curve to be evaluated at
+ */
+ if (fcu->bezt)
+ cvalue = fcurve_eval_keyframes(fcu, fcu->bezt, devaltime);
+ else if (fcu->fpt)
+ cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime);
+
+ /* evaluate modifiers */
+ evaluate_value_fmodifiers(storage, &fcu->modifiers, fcu, &cvalue, devaltime);
+
+ evaluate_fmodifiers_storage_free(storage);
+
+ /* if curve can only have integral values, perform truncation (i.e. drop the decimal part)
+ * here so that the curve can be sampled correctly
+ */
+ if (fcu->flag & FCURVE_INT_VALUES)
+ cvalue = floorf(cvalue + 0.5f);
- /* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime"
+ /* return evaluated value */
+ return cvalue;
+}
+
+float evaluate_fcurve(FCurve *fcu, float evaltime)
+{
+ BLI_assert(fcu->driver == NULL);
+
+ return evaluate_fcurve_ex(fcu, evaltime, 0.0);
+}
+
+float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime)
+{
+ BLI_assert(fcu->driver != NULL);
+ float cvalue = 0.0f;
+
+ /* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime"
* since drivers essentially act as alternative input (i.e. in place of 'time') for F-Curves
*/
if (fcu->driver) {
/* evaltime now serves as input for the curve */
- evaltime = evaluate_driver(fcu->driver, evaltime);
-
+ evaltime = evaluate_driver(anim_rna, fcu->driver, evaltime);
+
/* only do a default 1-1 mapping if it's unlikely that anything else will set a value... */
if (fcu->totvert == 0) {
FModifier *fcm;
bool do_linear = true;
-
- /* out-of-range F-Modifiers will block, as will those which just plain overwrite the values
+
+ /* out-of-range F-Modifiers will block, as will those which just plain overwrite the values
* XXX: additive is a bit more dicey; it really depends then if things are in range or not...
*/
for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) {
@@ -2634,7 +2675,7 @@ float evaluate_fcurve(FCurve *fcu, float evaltime)
do_linear = false;
}
}
-
+
/* only copy over results if none of the modifiers disagreed with this */
if (do_linear) {
cvalue = evaltime;
@@ -2642,36 +2683,11 @@ float evaluate_fcurve(FCurve *fcu, float evaltime)
}
}
- /* evaluate modifiers which modify time to evaluate the base curve at */
- storage = evaluate_fmodifiers_storage_new(&fcu->modifiers);
- devaltime = evaluate_time_fmodifiers(storage, &fcu->modifiers, fcu, cvalue, evaltime);
-
- /* evaluate curve-data
- * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying
- * F-Curve modifier on the stack requested the curve to be evaluated at
- */
- if (fcu->bezt)
- cvalue = fcurve_eval_keyframes(fcu, fcu->bezt, devaltime);
- else if (fcu->fpt)
- cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime);
-
- /* evaluate modifiers */
- evaluate_value_fmodifiers(storage, &fcu->modifiers, fcu, &cvalue, devaltime);
-
- evaluate_fmodifiers_storage_free(storage);
-
- /* if curve can only have integral values, perform truncation (i.e. drop the decimal part)
- * here so that the curve can be sampled correctly
- */
- if (fcu->flag & FCURVE_INT_VALUES)
- cvalue = floorf(cvalue + 0.5f);
-
- /* return evaluated value */
- return cvalue;
+ return evaluate_fcurve_ex(fcu, evaltime, cvalue);
}
/* Calculate the value of the given F-Curve at the given frame, and set its curval */
-float calculate_fcurve(FCurve *fcu, float evaltime)
+float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime)
{
/* only calculate + set curval (overriding the existing value) if curve has
* any data which warrants this...
@@ -2680,7 +2696,13 @@ float calculate_fcurve(FCurve *fcu, float evaltime)
list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE))
{
/* calculate and set curval (evaluates driver too if necessary) */
- float curval = evaluate_fcurve(fcu, evaltime);
+ float curval;
+ if (fcu->driver) {
+ curval = evaluate_fcurve_driver(anim_rna, fcu, evaltime);
+ }
+ else {
+ curval = evaluate_fcurve(fcu, evaltime);
+ }
fcu->curval = curval; /* debug display only, not thread safe! */
return curval;
}
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 8621da0d42e..e4bac0a947a 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2008, Blender Foundation
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -44,10 +44,12 @@
#include "DNA_gpencil_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_scene_types.h"
#include "BKE_animsys.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
+#include "BKE_colortools.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -57,76 +59,155 @@
/* --------- Memory Management ------------ */
+/* free stroke, doesn't unlink from any listbase */
+void BKE_gpencil_free_stroke(bGPDstroke *gps)
+{
+ if (gps == NULL) {
+ return;
+ }
+
+ /* free stroke memory arrays, then stroke itself */
+ if (gps->points)
+ MEM_freeN(gps->points);
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
+
+ MEM_freeN(gps);
+}
+
/* Free strokes belonging to a gp-frame */
-bool free_gpencil_strokes(bGPDframe *gpf)
+bool BKE_gpencil_free_strokes(bGPDframe *gpf)
{
- bGPDstroke *gps, *gpsn;
+ bGPDstroke *gps_next;
bool changed = (BLI_listbase_is_empty(&gpf->strokes) == false);
/* free strokes */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- /* 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);
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+ BKE_gpencil_free_stroke(gps);
}
+ BLI_listbase_clear(&gpf->strokes);
return changed;
}
/* Free all of a gp-layer's frames */
-void free_gpencil_frames(bGPDlayer *gpl)
+void BKE_gpencil_free_frames(bGPDlayer *gpl)
{
- bGPDframe *gpf, *gpfn;
+ bGPDframe *gpf_next;
/* error checking */
if (gpl == NULL) return;
/* free frames */
- for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
- gpfn = gpf->next;
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf_next) {
+ gpf_next = gpf->next;
/* free strokes and their associated memory */
- free_gpencil_strokes(gpf);
+ BKE_gpencil_free_strokes(gpf);
BLI_freelinkN(&gpl->frames, gpf);
}
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)
+{
+ 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);
+}
+
+/* Free all of the gp-brushes for a viewport (list should be &gpd->brushes or so) */
+void BKE_gpencil_free_brushes(ListBase *list)
+{
+ bGPDbrush *brush_next;
+
+ /* error checking */
+ if (list == 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);
+ }
+ 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 free_gpencil_layers(ListBase *list)
+void BKE_gpencil_free_layers(ListBase *list)
{
- bGPDlayer *gpl, *gpln;
+ bGPDlayer *gpl_next;
/* error checking */
if (list == NULL) return;
/* delete layers */
- for (gpl = list->first; gpl; gpl = gpln) {
- gpln = gpl->next;
+ for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) {
+ gpl_next = gpl->next;
/* free layers and their data */
- free_gpencil_frames(gpl);
+ BKE_gpencil_free_frames(gpl);
BLI_freelinkN(list, gpl);
}
}
-/* Free all of GPencil datablock's related data, but not the block itself */
/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
-void BKE_gpencil_free(bGPdata *gpd)
+void BKE_gpencil_free(bGPdata *gpd, bool free_palettes)
{
BKE_animdata_free(&gpd->id, false);
/* free layers */
- free_gpencil_layers(&gpd->layers);
+ BKE_gpencil_free_layers(&gpd->layers);
+
+ /* free palettes */
+ if (free_palettes) {
+ BKE_gpencil_free_palettes(&gpd->palettes);
+ }
}
/* -------- Container Creation ---------- */
/* add a new gp-frame to the given layer */
-bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
+bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
{
bGPDframe *gpf = NULL, *gf = NULL;
short state = 0;
@@ -178,9 +259,9 @@ bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
}
/* add a copy of the active gp-frame to the given layer */
-bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
+bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
{
- bGPDframe *new_frame, *gpf;
+ bGPDframe *new_frame;
bool found = false;
/* Error checking/handling */
@@ -190,14 +271,14 @@ bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
}
else if (gpl->actframe == NULL) {
/* no active frame, so just create a new one from scratch */
- return gpencil_frame_addnew(gpl, cframe);
+ return BKE_gpencil_frame_addnew(gpl, cframe);
}
/* Create a copy of the frame */
- new_frame = gpencil_frame_duplicate(gpl->actframe);
+ new_frame = BKE_gpencil_frame_duplicate(gpl->actframe);
/* Find frame to insert it before */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
if (gpf->framenum > cframe) {
/* Add it here */
BLI_insertlinkbefore(&gpl->frames, gpf, new_frame);
@@ -209,7 +290,7 @@ bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
/* This only happens when we're editing with framelock on...
* - Delete the new frame and don't do anything else here...
*/
- free_gpencil_strokes(new_frame);
+ BKE_gpencil_free_strokes(new_frame);
MEM_freeN(new_frame);
new_frame = NULL;
@@ -233,7 +314,7 @@ bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
}
/* add a new gp-layer and make it the active layer */
-bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
+bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
{
bGPDlayer *gpl;
@@ -249,8 +330,11 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
/* set basic settings */
copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
- gpl->thickness = 3;
-
+ /* Since GPv2 thickness must be 0 */
+ gpl->thickness = 0;
+
+ gpl->opacity = 1.0f;
+
/* onion-skinning settings */
if (gpd->flag & GP_DATA_SHOW_ONIONSKINS)
gpl->flag |= GP_LAYER_ONIONSKIN;
@@ -263,23 +347,280 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
/* high quality fill by default */
gpl->flag |= GP_LAYER_HQ_FILL;
- /* default smooth iterations */
- gpl->draw_smoothlvl = 1;
-
/* auto-name */
BLI_strncpy(gpl->info, name, sizeof(gpl->info));
BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
/* make this one the active one */
if (setactive)
- gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_setactive(gpd, gpl);
/* return layer */
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 */
+ if (setactive) {
+ 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)
+{
+ 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;
+
+ brush->draw_smoothfac = 1.1f;
+ brush->draw_smoothlvl = 2;
+ brush->sublevel = 2;
+ brush->draw_random_sub = 0.0f;
+
+ /* 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;
+
+ brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+ brush->draw_strength = 1.0f;
+ brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->draw_random_press = 1.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.1f;
+ brush->draw_smoothlvl = 2;
+ brush->sublevel = 2;
+ brush->draw_random_sub = 0.0f;
+
+ /* 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;
+
+ brush->draw_random_press = 0.0f;
+
+ brush->draw_jitter = 0.0f;
+ brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->draw_angle = M_PI_4; /* 45 degrees */
+ brush->draw_angle_factor = 1.0f;
+
+ brush->draw_smoothfac = 1.0f;
+ brush->draw_smoothlvl = 2;
+ brush->sublevel = 2;
+ brush->draw_random_sub = 0.0f;
+
+ /* 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;
+
+ brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+ brush->draw_strength = 0.140f;
+ 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 = 2;
+ brush->draw_random_sub = 0.5f;
+
+}
+
+/* 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;
+}
+
+/* add a new gp-palettecolor and make it the active */
+bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(bGPDpalette *palette, const char *name, bool setactive)
+{
+ 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 */
+ 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);
+
+ /* auto-name */
+ BLI_strncpy(palcolor->info, name, sizeof(palcolor->info));
+ BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
+ sizeof(palcolor->info));
+
+ /* 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 *gpencil_data_addnew(const char name[])
+bGPdata *BKE_gpencil_data_addnew(const char name[])
{
bGPdata *gpd;
@@ -300,94 +641,157 @@ bGPdata *gpencil_data_addnew(const char name[])
/* -------- Data Duplication ---------- */
/* make a copy of a given gpencil frame */
-bGPDframe *gpencil_frame_duplicate(bGPDframe *src)
+bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
{
- bGPDstroke *gps, *gpsd;
- bGPDframe *dst;
+ bGPDstroke *gps_dst;
+ bGPDframe *gpf_dst;
/* error checking */
- if (src == NULL)
+ if (gpf_src == NULL) {
return NULL;
+ }
/* make a copy of the source frame */
- dst = MEM_dupallocN(src);
- dst->prev = dst->next = NULL;
+ gpf_dst = MEM_dupallocN(gpf_src);
+ gpf_dst->prev = gpf_dst->next = NULL;
/* copy strokes */
- BLI_listbase_clear(&dst->strokes);
- for (gps = src->strokes.first; gps; gps = gps->next) {
+ 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 */
- gpsd = MEM_dupallocN(gps);
- gpsd->points = MEM_dupallocN(gps->points);
- gpsd->triangles = MEM_dupallocN(gps->triangles);
- gpsd->flag |= GP_STROKE_RECALC_CACHES;
- BLI_addtail(&dst->strokes, gpsd);
+ 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;
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
}
/* return new frame */
- return dst;
+ return gpf_dst;
+}
+
+/* make a copy of a given gpencil brush */
+bGPDbrush *BKE_gpencil_brush_duplicate(const bGPDbrush *brush_src)
+{
+ bGPDbrush *brush_dst;
+
+ /* 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;
+ }
+
+ /* 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);
+ }
+
+ /* return new palette */
+ return palette_dst;
+}
/* make a copy of a given gpencil layer */
-bGPDlayer *gpencil_layer_duplicate(bGPDlayer *src)
+bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
{
- bGPDframe *gpf, *gpfd;
- bGPDlayer *dst;
+ const bGPDframe *gpf_src;
+ bGPDframe *gpf_dst;
+ bGPDlayer *gpl_dst;
/* error checking */
- if (src == NULL)
+ if (gpl_src == NULL) {
return NULL;
+ }
/* make a copy of source layer */
- dst = MEM_dupallocN(src);
- dst->prev = dst->next = NULL;
+ gpl_dst = MEM_dupallocN(gpl_src);
+ gpl_dst->prev = gpl_dst->next = NULL;
/* copy frames */
- BLI_listbase_clear(&dst->frames);
- for (gpf = src->frames.first; gpf; gpf = gpf->next) {
+ BLI_listbase_clear(&gpl_dst->frames);
+ for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
/* make a copy of source frame */
- gpfd = gpencil_frame_duplicate(gpf);
- BLI_addtail(&dst->frames, gpfd);
+ gpf_dst = BKE_gpencil_frame_duplicate(gpf_src);
+ BLI_addtail(&gpl_dst->frames, gpf_dst);
/* if source frame was the current layer's 'active' frame, reassign that too */
- if (gpf == dst->actframe)
- dst->actframe = gpfd;
+ if (gpf_src == gpl_dst->actframe)
+ gpl_dst->actframe = gpf_dst;
}
/* return new layer */
- return dst;
+ return gpl_dst;
}
/* make a copy of a given gpencil datablock */
-bGPdata *gpencil_data_duplicate(Main *bmain, bGPdata *src, bool internal_copy)
+bGPdata *BKE_gpencil_data_duplicate(Main *bmain, bGPdata *gpd_src, bool internal_copy)
{
- bGPDlayer *gpl, *gpld;
- bGPdata *dst;
-
+ const bGPDlayer *gpl_src;
+ bGPDlayer *gpl_dst;
+ bGPdata *gpd_dst;
+
/* error checking */
- if (src == NULL)
+ if (gpd_src == NULL) {
return NULL;
+ }
/* make a copy of the base-data */
if (internal_copy) {
/* make a straight copy for undo buffers used during stroke drawing */
- dst = MEM_dupallocN(src);
+ gpd_dst = MEM_dupallocN(gpd_src);
}
else {
/* make a copy when others use this */
- dst = BKE_libblock_copy(bmain, &src->id);
+ gpd_dst = BKE_libblock_copy(bmain, &gpd_src->id);
}
/* copy layers */
- BLI_listbase_clear(&dst->layers);
- for (gpl = src->layers.first; gpl; gpl = gpl->next) {
+ 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 */
- gpld = gpencil_layer_duplicate(gpl);
- BLI_addtail(&dst->layers, gpld);
+ gpl_dst = BKE_gpencil_layer_duplicate(gpl_src);
+ BLI_addtail(&gpd_dst->layers, gpl_dst);
+ }
+ if (!internal_copy) {
+ /* copy palettes */
+ bGPDpalette *palette_src, *palette_dst;
+ BLI_listbase_clear(&gpd_dst->palettes);
+ for (palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) {
+ palette_dst = BKE_gpencil_palette_duplicate(palette_src);
+ BLI_addtail(&gpd_dst->palettes, palette_dst);
+ }
}
/* return new */
- return dst;
+ return gpd_dst;
}
void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
@@ -398,7 +802,7 @@ void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
/* -------- GP-Stroke API --------- */
/* ensure selection status of stroke is in sync with its points */
-void gpencil_stroke_sync_selection(bGPDstroke *gps)
+void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps)
{
bGPDspoint *pt;
int i;
@@ -423,7 +827,7 @@ void gpencil_stroke_sync_selection(bGPDstroke *gps)
/* -------- GP-Frame API ---------- */
/* delete the last stroke of the given frame */
-void gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
+void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
{
bGPDstroke *gps = (gpf) ? gpf->strokes.last : NULL;
int cfra = (gpf) ? gpf->framenum : 0; /* assume that the current frame was not locked */
@@ -439,8 +843,8 @@ void gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
/* if frame has no strokes after this, delete it */
if (BLI_listbase_is_empty(&gpf->strokes)) {
- gpencil_layer_delframe(gpl, gpf);
- gpencil_layer_getframe(gpl, cfra, 0);
+ BKE_gpencil_layer_delframe(gpl, gpf);
+ BKE_gpencil_layer_getframe(gpl, cfra, 0);
}
}
@@ -458,7 +862,7 @@ bool gpencil_layer_is_editable(const bGPDlayer *gpl)
/* Opacity must be sufficiently high that it is still "visible"
* Otherwise, it's not really "visible" to the user, so no point editing...
*/
- if ((gpl->color[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH)) {
+ if (gpl->opacity > GPENCIL_ALPHA_OPACITY_THRESH) {
return true;
}
}
@@ -488,7 +892,7 @@ bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe)
* - this sets the layer's actframe var (if allowed to)
* - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
*/
-bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
+bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
{
bGPDframe *gpf = NULL;
short found = 0;
@@ -527,9 +931,9 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode
if ((found) && (gpf->framenum == cframe))
gpl->actframe = gpf;
else if (addnew == GP_GETFRAME_ADD_COPY)
- gpl->actframe = gpencil_frame_addcopy(gpl, cframe);
+ gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
else
- gpl->actframe = gpencil_frame_addnew(gpl, cframe);
+ gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
}
else if (found)
gpl->actframe = gpf;
@@ -549,9 +953,9 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode
if ((found) && (gpf->framenum == cframe))
gpl->actframe = gpf;
else if (addnew == GP_GETFRAME_ADD_COPY)
- gpl->actframe = gpencil_frame_addcopy(gpl, cframe);
+ gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
else
- gpl->actframe = gpencil_frame_addnew(gpl, cframe);
+ gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
}
else if (found)
gpl->actframe = gpf;
@@ -588,7 +992,7 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode
if ((found) && (gpf->framenum == cframe))
gpl->actframe = gpf;
else
- gpl->actframe = gpencil_frame_addnew(gpl, cframe);
+ gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
}
else if (found)
gpl->actframe = gpf;
@@ -601,7 +1005,7 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode
else {
/* currently no frames (add if allowed to) */
if (addnew)
- gpl->actframe = gpencil_frame_addnew(gpl, cframe);
+ gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
else {
/* don't do anything... this may be when no frames yet! */
/* gpl->actframe should still be NULL */
@@ -613,7 +1017,7 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode
}
/* delete the given frame from a layer */
-bool gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf)
+bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf)
{
bool changed = false;
@@ -630,14 +1034,14 @@ bool gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf)
gpl->actframe = NULL;
/* free the frame and its data */
- changed = free_gpencil_strokes(gpf);
+ changed = BKE_gpencil_free_strokes(gpf);
BLI_freelinkN(&gpl->frames, gpf);
return changed;
}
/* get the active gp-layer for editing */
-bGPDlayer *gpencil_layer_getactive(bGPdata *gpd)
+bGPDlayer *BKE_gpencil_layer_getactive(bGPdata *gpd)
{
bGPDlayer *gpl;
@@ -656,7 +1060,7 @@ bGPDlayer *gpencil_layer_getactive(bGPdata *gpd)
}
/* set the active gp-layer */
-void gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active)
+void BKE_gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active)
{
bGPDlayer *gpl;
@@ -673,15 +1077,255 @@ void gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active)
}
/* delete the active gp-layer */
-void gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
+void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
{
/* error checking */
if (ELEM(NULL, gpd, gpl))
return;
/* free layer */
- free_gpencil_frames(gpl);
+ BKE_gpencil_free_frames(gpl);
BLI_freelinkN(&gpd->layers, gpl);
}
/* ************************************************** */
+/* get the active gp-brush for editing */
+bGPDbrush *BKE_gpencil_brush_getactive(ToolSettings *ts)
+{
+ bGPDbrush *brush;
+
+ /* error checking */
+ if (ELEM(NULL, ts, ts->gp_brushes.first)) {
+ return NULL;
+ }
+
+ /* 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;
+ }
+ }
+
+ /* no active brush found */
+ return NULL;
+}
+
+/* set the active gp-brush */
+void BKE_gpencil_brush_setactive(ToolSettings *ts, bGPDbrush *active)
+{
+ bGPDbrush *brush;
+
+ /* error checking */
+ if (ELEM(NULL, ts, ts->gp_brushes.first, active)) {
+ return;
+ }
+
+ /* loop over brushes deactivating all */
+ for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
+ brush->flag &= ~GP_BRUSH_ACTIVE;
+ }
+
+ /* set as active one */
+ active->flag |= GP_BRUSH_ACTIVE;
+}
+
+/* delete the active gp-brush */
+void BKE_gpencil_brush_delete(ToolSettings *ts, bGPDbrush *brush)
+{
+ /* error checking */
+ if (ELEM(NULL, ts, brush)) {
+ return;
+ }
+
+ /* free curves */
+ if (brush->cur_sensitivity) {
+ curvemapping_free(brush->cur_sensitivity);
+ }
+ if (brush->cur_strength) {
+ curvemapping_free(brush->cur_strength);
+ }
+ if (brush->cur_jitter) {
+ curvemapping_free(brush->cur_jitter);
+ }
+
+ /* free */
+ BLI_freelinkN(&ts->gp_brushes, brush);
+}
+
+/* ************************************************** */
+/* get the active gp-palette for editing */
+bGPDpalette *BKE_gpencil_palette_getactive(bGPdata *gpd)
+{
+ bGPDpalette *palette;
+
+ /* error checking */
+ if (ELEM(NULL, gpd, gpd->palettes.first)) {
+ 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;
+ }
+
+ /* no active palette found */
+ return NULL;
+}
+
+/* set the active gp-palette */
+void BKE_gpencil_palette_setactive(bGPdata *gpd, bGPDpalette *active)
+{
+ bGPDpalette *palette;
+
+ /* error checking */
+ if (ELEM(NULL, gpd, gpd->palettes.first, active)) {
+ return;
+ }
+
+ /* loop over palettes deactivating all */
+ for (palette = gpd->palettes.first; palette; palette = palette->next) {
+ palette->flag &= ~PL_PALETTE_ACTIVE;
+ }
+
+ /* set as active one */
+ active->flag |= PL_PALETTE_ACTIVE;
+ /* force color recalc */
+ BKE_gpencil_palette_change_strokes(gpd);
+}
+
+/* delete the active gp-palette */
+void BKE_gpencil_palette_delete(bGPdata *gpd, bGPDpalette *palette)
+{
+ /* error checking */
+ if (ELEM(NULL, gpd, palette)) {
+ return;
+ }
+
+ /* free colors */
+ free_gpencil_colors(palette);
+ BLI_freelinkN(&gpd->palettes, palette);
+ /* force color recalc */
+ BKE_gpencil_palette_change_strokes(gpd);
+}
+
+/* Set all strokes to recalc the palette color */
+void BKE_gpencil_palette_change_strokes(bGPdata *gpd)
+{
+ bGPDlayer *gpl;
+ bGPDframe *gpf;
+ bGPDstroke *gps;
+
+ 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;
+ }
+ }
+ }
+}
+
+
+/* get the active gp-palettecolor for editing */
+bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(bGPDpalette *palette)
+{
+ bGPDpalettecolor *palcolor;
+
+ /* error checking */
+ if (ELEM(NULL, palette, palette->colors.first)) {
+ return NULL;
+ }
+
+ /* 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;
+ }
+ }
+
+ /* no active color found */
+ return NULL;
+}
+/* get the gp-palettecolor looking for name */
+bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(bGPDpalette *palette, char *name)
+{
+ /* error checking */
+ if (ELEM(NULL, palette, name)) {
+ return NULL;
+ }
+
+ return BLI_findstring(&palette->colors, name, offsetof(bGPDpalettecolor, info));
+}
+
+/* Change color name in all strokes */
+void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char *newname)
+{
+ bGPDlayer *gpl;
+ bGPDframe *gpf;
+ bGPDstroke *gps;
+
+ 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)) {
+ strcpy(gps->colorname, newname);
+ }
+ }
+ }
+ }
+
+}
+
+/* Delete all strokes of the color */
+void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name)
+{
+ bGPDlayer *gpl;
+ bGPDframe *gpf;
+ bGPDstroke *gps, *gpsn;
+
+ 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);
+ }
+ }
+ }
+ }
+
+}
+
+/* set the active gp-palettecolor */
+void BKE_gpencil_palettecolor_setactive(bGPDpalette *palette, bGPDpalettecolor *active)
+{
+ bGPDpalettecolor *palcolor;
+
+ /* error checking */
+ if (ELEM(NULL, palette, palette->colors.first, active)) {
+ return;
+ }
+
+ /* loop over colors deactivating all */
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ palcolor->flag &= ~PC_COLOR_ACTIVE;
+ }
+
+ /* set as active one */
+ active->flag |= PC_COLOR_ACTIVE;
+}
+
+/* delete the active gp-palettecolor */
+void BKE_gpencil_palettecolor_delete(bGPDpalette *palette, bGPDpalettecolor *palcolor)
+{
+ /* error checking */
+ if (ELEM(NULL, palette, palcolor)) {
+ return;
+ }
+
+ /* free */
+ BLI_freelinkN(&palette->colors, palcolor);
+}
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index f58d26f47dc..9b011dbb003 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -97,10 +97,7 @@ Group *BKE_group_copy(Main *bmain, Group *group)
/* Do not copy group's preview (same behavior as for objects). */
groupn->preview = NULL;
- if (ID_IS_LINKED_DATABLOCK(group)) {
- BKE_id_expand_local(&groupn->id);
- BKE_id_lib_local_paths(bmain, group->id.lib, &groupn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &group->id, &groupn->id);
return groupn;
}
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index 90b3713e47c..70d037d85f3 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -60,6 +60,7 @@ static IDType idtypes[] = {
{ ID_AR, "Armature", "armatures", BLT_I18NCONTEXT_ID_ARMATURE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE },
{ ID_CA, "Camera", "cameras", BLT_I18NCONTEXT_ID_CAMERA, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_CF, "CacheFile", "cache_files", BLT_I18NCONTEXT_ID_CACHEFILE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */
{ ID_GR, "Group", "groups", BLT_I18NCONTEXT_ID_GROUP, IDTYPE_FLAGS_ISLINKABLE },
@@ -184,6 +185,7 @@ int BKE_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(AR);
CASE_IDFILTER(BR);
CASE_IDFILTER(CA);
+ CASE_IDFILTER(CF);
CASE_IDFILTER(CU);
CASE_IDFILTER(GD);
CASE_IDFILTER(GR);
@@ -227,6 +229,7 @@ short BKE_idcode_from_idfilter(const int idfilter)
CASE_IDFILTER(AR);
CASE_IDFILTER(BR);
CASE_IDFILTER(CA);
+ CASE_IDFILTER(CF);
CASE_IDFILTER(CU);
CASE_IDFILTER(GD);
CASE_IDFILTER(GR);
@@ -259,6 +262,56 @@ short BKE_idcode_from_idfilter(const int idfilter)
}
/**
+ * Convert an idcode into an index (e.g. ID_OB -> INDEX_ID_OB).
+ */
+int BKE_idcode_to_index(const short idcode)
+{
+#define CASE_IDINDEX(_id) case ID_##_id: return INDEX_ID_##_id
+
+ switch ((ID_Type)idcode) {
+ CASE_IDINDEX(AC);
+ CASE_IDINDEX(AR);
+ CASE_IDINDEX(BR);
+ CASE_IDINDEX(CA);
+ CASE_IDINDEX(CF);
+ CASE_IDINDEX(CU);
+ CASE_IDINDEX(GD);
+ CASE_IDINDEX(GR);
+ CASE_IDINDEX(IM);
+ CASE_IDINDEX(KE);
+ CASE_IDINDEX(IP);
+ CASE_IDINDEX(LA);
+ CASE_IDINDEX(LI);
+ CASE_IDINDEX(LS);
+ CASE_IDINDEX(LT);
+ CASE_IDINDEX(MA);
+ CASE_IDINDEX(MB);
+ CASE_IDINDEX(MC);
+ CASE_IDINDEX(ME);
+ CASE_IDINDEX(MSK);
+ CASE_IDINDEX(NT);
+ CASE_IDINDEX(OB);
+ CASE_IDINDEX(PA);
+ CASE_IDINDEX(PAL);
+ CASE_IDINDEX(PC);
+ CASE_IDINDEX(SCE);
+ CASE_IDINDEX(SCR);
+ CASE_IDINDEX(SPK);
+ CASE_IDINDEX(SO);
+ CASE_IDINDEX(TE);
+ CASE_IDINDEX(TXT);
+ CASE_IDINDEX(VF);
+ CASE_IDINDEX(WM);
+ CASE_IDINDEX(WO);
+ }
+
+ BLI_assert(0);
+ return -1;
+
+#undef CASE_IDINDEX
+}
+
+/**
* Convert an idcode into a name (plural).
*
* \param idcode: The code to convert.
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 86d010f5f7c..b2641b110f8 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -940,17 +940,18 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
prop->subtype = IDP_STRING_SUB_BYTE;
}
else {
- if (st == NULL) {
+ if (st == NULL || val->string.len <= 1) {
prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
*IDP_String(prop) = '\0';
prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/
}
else {
- int stlen = (int)strlen(st) + 1;
- prop->data.pointer = MEM_mallocN((size_t)stlen, "id property string 3");
- prop->len = prop->totallen = stlen;
- memcpy(prop->data.pointer, st, (size_t)stlen);
+ BLI_assert((int)val->string.len <= (int)strlen(st) + 1);
+ prop->data.pointer = MEM_mallocN((size_t)val->string.len, "id property string 3");
+ memcpy(prop->data.pointer, st, (size_t)val->string.len - 1);
+ IDP_String(prop)[val->string.len - 1] = '\0';
+ prop->len = prop->totallen = val->string.len;
}
prop->subtype = IDP_STRING_SUB_UTF8;
}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index b1fc9e0fbe0..93d835c34e4 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -436,6 +436,7 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
Image *BKE_image_copy(Main *bmain, Image *ima)
{
Image *nima = image_alloc(bmain, ima->id.name + 2, ima->source, ima->type);
+ ima->id.newid = &nima->id;
BLI_strncpy(nima->name, ima->name, sizeof(ima->name));
@@ -462,10 +463,7 @@ Image *BKE_image_copy(Main *bmain, Image *ima)
BKE_previewimg_id_copy(&nima->id, &ima->id);
- if (ID_IS_LINKED_DATABLOCK(ima)) {
- BKE_id_expand_local(&nima->id);
- BKE_id_lib_local_paths(bmain, ima->id.lib, &nima->id);
- }
+ BKE_id_copy_ensure_local(bmain, &ima->id, &nima->id);
return nima;
}
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index a524f927cad..6cdeaf5e59b 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -170,10 +170,7 @@ Key *BKE_key_copy(Main *bmain, Key *key)
kb = kb->next;
}
- if (ID_IS_LINKED_DATABLOCK(key)) {
- BKE_id_expand_local(&keyn->id);
- BKE_id_lib_local_paths(bmain, key->id.lib, &keyn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &key->id, &keyn->id);
return keyn;
}
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 35fcf211b05..e9d039ad480 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -138,10 +138,7 @@ Lamp *BKE_lamp_copy(Main *bmain, Lamp *la)
BKE_previewimg_id_copy(&lan->id, &la->id);
- if (ID_IS_LINKED_DATABLOCK(la)) {
- BKE_id_expand_local(&lan->id);
- BKE_id_lib_local_paths(bmain, la->id.lib, &lan->id);
- }
+ BKE_id_copy_ensure_local(bmain, &la->id, &lan->id);
return lan;
}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 82b179d4f1c..b0671f33094 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -297,10 +297,7 @@ Lattice *BKE_lattice_copy(Main *bmain, Lattice *lt)
ltn->editlatt = NULL;
- if (ID_IS_LINKED_DATABLOCK(lt)) {
- BKE_id_expand_local(&ltn->id);
- BKE_id_lib_local_paths(bmain, lt->id.lib, &ltn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &lt->id, &ltn->id);
return ltn;
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index c31df685136..6d94cd28b31 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -45,6 +45,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_camera_types.h"
#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
@@ -56,6 +57,7 @@
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
@@ -81,6 +83,7 @@
#include "BKE_bpath.h"
#include "BKE_brush.h"
#include "BKE_camera.h"
+#include "BKE_cachefile.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
@@ -103,8 +106,10 @@
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_mask.h"
+#include "BKE_movieclip.h"
#include "BKE_node.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_packedFile.h"
#include "BKE_sound.h"
@@ -272,6 +277,17 @@ void BKE_id_expand_local(ID *id)
}
/**
+ * Ensure new (copied) ID is fully made local.
+ */
+void BKE_id_copy_ensure_local(Main *bmain, ID *old_id, ID *new_id)
+{
+ if (ID_IS_LINKED_DATABLOCK(old_id)) {
+ BKE_id_expand_local(new_id);
+ BKE_id_lib_local_paths(bmain, old_id->lib, new_id);
+ }
+}
+
+/**
* Generic 'make local' function, works for most of datablock types...
*/
void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, const bool lib_local)
@@ -308,7 +324,6 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
}
}
}
-
}
/**
@@ -320,16 +335,16 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
*/
bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
{
- if (id->tag & LIB_TAG_INDIRECT)
+ /* We don't care whether ID is directly or indirectly linked in case we are making a whole lib local... */
+ if (!lib_local && (id->tag & LIB_TAG_INDIRECT)) {
return false;
+ }
- switch (GS(id->name)) {
+ switch ((ID_Type)GS(id->name)) {
case ID_SCE:
/* Partially implemented (has no copy...). */
if (!test) BKE_scene_make_local(bmain, (Scene *)id, lib_local);
return true;
- case ID_LI:
- return false; /* can't be linked */
case ID_OB:
if (!test) BKE_object_make_local(bmain, (Object *)id, lib_local);
return true;
@@ -363,15 +378,9 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
case ID_SPK:
if (!test) BKE_speaker_make_local(bmain, (Speaker *)id, lib_local);
return true;
- case ID_IP:
- return false; /* deprecated */
- case ID_KE:
- return false; /* can't be linked */
case ID_WO:
if (!test) BKE_world_make_local(bmain, (World *)id, lib_local);
return true;
- case ID_SCR:
- return false; /* can't be linked */
case ID_VF:
/* Partially implemented (has no copy...). */
if (!test) BKE_vfont_make_local(bmain, (VFont *)id, lib_local);
@@ -401,17 +410,34 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
case ID_PA:
if (!test) BKE_particlesettings_make_local(bmain, (ParticleSettings *)id, lib_local);
return true;
- case ID_WM:
- return false; /* can't be linked */
case ID_GD:
if (!test) BKE_gpencil_make_local(bmain, (bGPdata *)id, lib_local);
return true;
+ case ID_MC:
+ if (!test) BKE_movieclip_make_local(bmain, (MovieClip *)id, lib_local);
+ return true;
case ID_MSK:
if (!test) BKE_mask_make_local(bmain, (Mask *)id, lib_local);
return true;
case ID_LS:
if (!test) BKE_linestyle_make_local(bmain, (FreestyleLineStyle *)id, lib_local);
return true;
+ case ID_PAL:
+ if (!test) BKE_palette_make_local(bmain, (Palette *)id, lib_local);
+ return true;
+ case ID_PC:
+ if (!test) BKE_paint_curve_make_local(bmain, (PaintCurve *)id, lib_local);
+ return true;
+ case ID_CF:
+ if (!test) BKE_cachefile_make_local(bmain, (CacheFile *)id, lib_local);
+ return true;
+ case ID_SCR:
+ case ID_LI:
+ case ID_KE:
+ case ID_WM:
+ return false; /* can't be linked */
+ case ID_IP:
+ return false; /* deprecated */
}
return false;
@@ -430,11 +456,7 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
/* conventions:
* - make shallow copy, only this ID block
* - id.us of the new ID is set to 1 */
- switch (GS(id->name)) {
- case ID_SCE:
- return false; /* can't be copied from here */
- case ID_LI:
- return false; /* can't be copied from here */
+ switch ((ID_Type)GS(id->name)) {
case ID_OB:
if (!test) *newid = (ID *)BKE_object_copy(bmain, (Object *)id);
return true;
@@ -468,23 +490,15 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
case ID_CA:
if (!test) *newid = (ID *)BKE_camera_copy(bmain, (Camera *)id);
return true;
- case ID_IP:
- return false; /* deprecated */
case ID_KE:
if (!test) *newid = (ID *)BKE_key_copy(bmain, (Key *)id);
return true;
case ID_WO:
if (!test) *newid = (ID *)BKE_world_copy(bmain, (World *)id);
return true;
- case ID_SCR:
- return false; /* can't be copied from here */
- case ID_VF:
- return false; /* not implemented */
case ID_TXT:
if (!test) *newid = (ID *)BKE_text_copy(bmain, (Text *)id);
return true;
- case ID_SO:
- return false; /* not implemented */
case ID_GR:
if (!test) *newid = (ID *)BKE_group_copy(bmain, (Group *)id);
return true;
@@ -503,10 +517,11 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
case ID_PA:
if (!test) *newid = (ID *)BKE_particlesettings_copy(bmain, (ParticleSettings *)id);
return true;
- case ID_WM:
- return false; /* can't be copied from here */
case ID_GD:
- if (!test) *newid = (ID *)gpencil_data_duplicate(bmain, (bGPdata *)id, false);
+ if (!test) *newid = (ID *)BKE_gpencil_data_duplicate(bmain, (bGPdata *)id, false);
+ return true;
+ case ID_MC:
+ if (!test) *newid = (ID *)BKE_movieclip_copy(bmain, (MovieClip *)id);
return true;
case ID_MSK:
if (!test) *newid = (ID *)BKE_mask_copy(bmain, (Mask *)id);
@@ -514,6 +529,25 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
case ID_LS:
if (!test) *newid = (ID *)BKE_linestyle_copy(bmain, (FreestyleLineStyle *)id);
return true;
+ case ID_PAL:
+ if (!test) *newid = (ID *)BKE_palette_copy(bmain, (Palette *)id);
+ return true;
+ case ID_PC:
+ if (!test) *newid = (ID *)BKE_paint_curve_copy(bmain, (PaintCurve *)id);
+ return true;
+ case ID_CF:
+ if (!test) *newid = (ID *)BKE_cachefile_copy(bmain, (CacheFile *)id);
+ return true;
+ case ID_SCE:
+ case ID_LI:
+ case ID_SCR:
+ case ID_WM:
+ return false; /* can't be copied from here */
+ case ID_VF:
+ case ID_SO:
+ return false; /* not implemented */
+ case ID_IP:
+ return false; /* deprecated */
}
return false;
@@ -549,7 +583,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
ListBase *which_libbase(Main *mainlib, short type)
{
- switch (type) {
+ switch ((ID_Type)type) {
case ID_SCE:
return &(mainlib->scene);
case ID_LI:
@@ -616,6 +650,8 @@ ListBase *which_libbase(Main *mainlib, short type)
return &(mainlib->palettes);
case ID_PC:
return &(mainlib->paintcurves);
+ case ID_CF:
+ return &(mainlib->cachefiles);
}
return NULL;
}
@@ -717,59 +753,56 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
* \note MAX_LIBARRAY define should match this code */
int set_listbasepointers(Main *main, ListBase **lb)
{
- int a = 0;
-
/* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last.
* This is important because freeing data decreases usercounts of other datablocks,
* if this data is its self freed it can crash. */
- lb[a++] = &(main->library); /* Libraries may be accessed from pretty much any other ID... */
- lb[a++] = &(main->ipo);
- lb[a++] = &(main->action); /* moved here to avoid problems when freeing with animato (aligorith) */
- lb[a++] = &(main->key);
- lb[a++] = &(main->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */
- lb[a++] = &(main->nodetree);
- lb[a++] = &(main->image);
- lb[a++] = &(main->tex);
- lb[a++] = &(main->mat);
- lb[a++] = &(main->vfont);
+ lb[INDEX_ID_LI] = &(main->library); /* Libraries may be accessed from pretty much any other ID... */
+ 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_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);
+ lb[INDEX_ID_TE] = &(main->tex);
+ lb[INDEX_ID_MA] = &(main->mat);
+ lb[INDEX_ID_VF] = &(main->vfont);
/* Important!: When adding a new object type,
* the specific data should be inserted here
*/
- lb[a++] = &(main->armature);
-
- lb[a++] = &(main->mesh);
- lb[a++] = &(main->curve);
- lb[a++] = &(main->mball);
-
- lb[a++] = &(main->latt);
- lb[a++] = &(main->lamp);
- lb[a++] = &(main->camera);
-
- lb[a++] = &(main->text);
- lb[a++] = &(main->sound);
- lb[a++] = &(main->group);
- lb[a++] = &(main->palettes);
- lb[a++] = &(main->paintcurves);
- lb[a++] = &(main->brush);
- lb[a++] = &(main->particle);
- lb[a++] = &(main->speaker);
-
- lb[a++] = &(main->world);
- lb[a++] = &(main->movieclip);
- lb[a++] = &(main->screen);
- lb[a++] = &(main->object);
- lb[a++] = &(main->linestyle); /* referenced by scenes */
- lb[a++] = &(main->scene);
- lb[a++] = &(main->wm);
- lb[a++] = &(main->mask);
+ lb[INDEX_ID_AR] = &(main->armature);
+
+ lb[INDEX_ID_CF] = &(main->cachefiles);
+ lb[INDEX_ID_ME] = &(main->mesh);
+ lb[INDEX_ID_CU] = &(main->curve);
+ lb[INDEX_ID_MB] = &(main->mball);
+
+ lb[INDEX_ID_LT] = &(main->latt);
+ lb[INDEX_ID_LA] = &(main->lamp);
+ lb[INDEX_ID_CA] = &(main->camera);
+
+ lb[INDEX_ID_TXT] = &(main->text);
+ lb[INDEX_ID_SO] = &(main->sound);
+ lb[INDEX_ID_GR] = &(main->group);
+ lb[INDEX_ID_PAL] = &(main->palettes);
+ lb[INDEX_ID_PC] = &(main->paintcurves);
+ lb[INDEX_ID_BR] = &(main->brush);
+ lb[INDEX_ID_PA] = &(main->particle);
+ lb[INDEX_ID_SPK] = &(main->speaker);
+
+ lb[INDEX_ID_WO] = &(main->world);
+ lb[INDEX_ID_MC] = &(main->movieclip);
+ lb[INDEX_ID_SCR] = &(main->screen);
+ lb[INDEX_ID_OB] = &(main->object);
+ lb[INDEX_ID_LS] = &(main->linestyle); /* referenced by scenes */
+ lb[INDEX_ID_SCE] = &(main->scene);
+ lb[INDEX_ID_WM] = &(main->wm);
+ lb[INDEX_ID_MSK] = &(main->mask);
- lb[a] = NULL;
-
- BLI_assert(a + 1 == MAX_LIBARRAY);
+ lb[INDEX_ID_NULL] = NULL;
- return a;
+ return (MAX_LIBARRAY - 1);
}
/* *********** ALLOC AND FREE *****************
@@ -790,7 +823,7 @@ void *BKE_libblock_alloc_notest(short type)
{
ID *id = NULL;
- switch (type) {
+ switch ((ID_Type)type) {
case ID_SCE:
id = MEM_callocN(sizeof(Scene), "scene");
break;
@@ -890,6 +923,9 @@ void *BKE_libblock_alloc_notest(short type)
case ID_PC:
id = MEM_callocN(sizeof(PaintCurve), "Paint Curve");
break;
+ case ID_CF:
+ id = MEM_callocN(sizeof(CacheFile), "Cache File");
+ break;
}
return id;
}
@@ -927,7 +963,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name)
void BKE_libblock_init_empty(ID *id)
{
/* Note that only ID types that are not valid when filled of zero should have a callback here. */
- switch (GS(id->name)) {
+ switch ((ID_Type)GS(id->name)) {
case ID_SCE:
BKE_scene_init((Scene *)id);
break;
@@ -971,15 +1007,6 @@ void BKE_libblock_init_empty(ID *id)
case ID_CA:
BKE_camera_init((Camera *)id);
break;
- case ID_IP:
- /* Should not be needed - animation from lib pre-2.5 is broken anyway. */
- BLI_assert(0);
- break;
- case ID_KE:
- /* Shapekeys are a complex topic too - they depend on their 'user' data type...
- * They are not linkable, though, so it should never reach here anyway. */
- BLI_assert(0);
- break;
case ID_WO:
BKE_world_init((World *)id);
break;
@@ -1016,10 +1043,6 @@ void BKE_libblock_init_empty(ID *id)
case ID_PC:
/* Nothing to do. */
break;
- case ID_WM:
- /* We should never reach this. */
- BLI_assert(0);
- break;
case ID_GD:
/* Nothing to do. */
break;
@@ -1029,6 +1052,24 @@ void BKE_libblock_init_empty(ID *id)
case ID_LS:
BKE_linestyle_init((FreestyleLineStyle *)id);
break;
+ case ID_CF:
+ BKE_cachefile_init((CacheFile *)id);
+ break;
+ case ID_KE:
+ /* Shapekeys are a complex topic too - they depend on their 'user' data type...
+ * They are not linkable, though, so it should never reach here anyway. */
+ BLI_assert(0);
+ break;
+ case ID_WM:
+ /* We should never reach this. */
+ BLI_assert(0);
+ break;
+ case ID_IP:
+ /* Should not be needed - animation from lib pre-2.5 is broken anyway. */
+ BLI_assert(0);
+ break;
+ default:
+ BLI_assert(0); /* Should never reach this point... */
}
}
@@ -1201,6 +1242,7 @@ void BKE_main_free(Main *mainvar)
case 31: BKE_libblock_free_ex(mainvar, id, false); break;
case 32: BKE_libblock_free_ex(mainvar, id, false); break;
case 33: BKE_libblock_free_ex(mainvar, id, false); break;
+ case 34: BKE_libblock_free_ex(mainvar, id, false); break;
default:
BLI_assert(0);
break;
@@ -1612,16 +1654,22 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
int a;
for (a = set_listbasepointers(bmain, lbarray); a--; ) {
- for (id = lbarray[a]->first; id; id = id_next) {
+ id = lbarray[a]->first;
+
+ /* Do not explicitly make local non-linkable IDs (shapekeys, in fact), they are assumed to be handled
+ * by real datablocks responsible of them. */
+ const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name)));
+
+ for (; id; id = id_next) {
id->newid = NULL;
id_next = id->next; /* id is possibly being inserted again */
-
+
/* The check on the second line (LIB_TAG_PRE_EXISTING) is done so its
* possible to tag data you don't want to be made local, used for
* appending data, so any libdata already linked wont become local
* (very nasty to discover all your links are lost after appending)
* */
- if (id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
+ if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
{
if (lib == NULL || id->lib == lib) {
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index 1ded6f6679f..cb864334208 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -305,7 +305,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
library_foreach_animationData(&data, adt);
}
- switch (GS(id->name)) {
+ switch ((ID_Type)GS(id->name)) {
case ID_LI:
{
Library *lib = (Library *) id;
@@ -499,8 +499,12 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data);
}
- if (object->soft && object->soft->effector_weights) {
- CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP);
+ if (object->soft) {
+ CALLBACK_INVOKE(object->soft->collision_group, IDWALK_NOP);
+
+ if (object->soft->effector_weights) {
+ CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP);
+ }
}
BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data);
@@ -639,6 +643,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_KE:
{
+ /* XXX Only ID pointer from shapekeys is the 'from' one, which is not actually ID usage.
+ * Maybe we should even nuke it from here, not 100% sure yet...
+ * (see also foreach_libblock_id_users_callback).
+ */
Key *key = (Key *) id;
CALLBACK_INVOKE_ID(key->from, IDWALK_NOP);
break;
@@ -711,6 +719,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE(psett->dup_group, IDWALK_NOP);
CALLBACK_INVOKE(psett->dup_ob, IDWALK_NOP);
CALLBACK_INVOKE(psett->bb_ob, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->collision_group, IDWALK_NOP);
for (i = 0; i < MAX_MTEX; i++) {
if (psett->mtex[i]) {
@@ -833,6 +842,25 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
break;
}
+
+ /* Nothing needed for those... */
+ case ID_IM:
+ case ID_VF:
+ case ID_TXT:
+ case ID_SO:
+ case ID_AR:
+ case ID_AC:
+ case ID_GD:
+ case ID_WM:
+ case ID_PAL:
+ case ID_PC:
+ case ID_CF:
+ break;
+
+ /* Deprecated. */
+ case ID_IP:
+ break;
+
}
} while ((id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL));
@@ -875,7 +903,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
return id_type_can_have_animdata(id_type_owner);
}
- switch (id_type_owner) {
+ switch ((ID_Type)id_type_owner) {
case ID_LI:
return ELEM(id_type_used, ID_LI);
case ID_SCE:
@@ -934,9 +962,24 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */
case ID_LS:
return (ELEM(id_type_used, ID_TE, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
- default:
+ case ID_IM:
+ case ID_VF:
+ case ID_TXT:
+ case ID_SO:
+ case ID_AR:
+ case ID_AC:
+ case ID_GD:
+ case ID_WM:
+ case ID_PAL:
+ case ID_PC:
+ case ID_CF:
+ /* Those types never use/reference other IDs... */
+ return false;
+ case ID_IP:
+ /* Deprecated... */
return false;
}
+ return false;
}
@@ -951,10 +994,18 @@ typedef struct IDUsersIter {
int count_direct, count_indirect; /* Set by callback. */
} IDUsersIter;
-static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int cb_flag)
+static int foreach_libblock_id_users_callback(void *user_data, ID *self_id, ID **id_p, int cb_flag)
{
IDUsersIter *iter = user_data;
+ /* XXX This is actually some kind of hack...
+ * Issue is, only ID pointer from shapekeys is the 'from' one, which is not actually ID usage.
+ * Maybe we should even nuke it from BKE_library_foreach_ID_link, not 100% sure yet...
+ */
+ if (GS(self_id->name) == ID_KE) {
+ return IDWALK_RET_NOP;
+ }
+
if (*id_p && (*id_p == iter->id)) {
#if 0
printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n",
@@ -1015,6 +1066,10 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
}
for (; id_curr && !is_defined; id_curr = id_curr->next) {
+ if (id_curr == id) {
+ /* We are not interested in self-usages (mostly from drivers or bone constraints...). */
+ continue;
+ }
iter.curr_id = id_curr;
BKE_library_foreach_ID_link(
id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
@@ -1063,6 +1118,10 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
}
for (; id_curr && !is_defined; id_curr = id_curr->next) {
+ if (id_curr == id) {
+ /* We are not interested in self-usages (mostly from drivers or bone constraints...). */
+ continue;
+ }
iter.curr_id = id_curr;
BKE_library_foreach_ID_link(id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 74b3b1b6c18..1830ca0bd90 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -38,6 +38,7 @@
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_ipo_types.h"
@@ -69,6 +70,7 @@
#include "BKE_armature.h"
#include "BKE_brush.h"
#include "BKE_camera.h"
+#include "BKE_cachefile.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
@@ -795,7 +797,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
free_windowmanager_cb(NULL, (wmWindowManager *)id);
break;
case ID_GD:
- BKE_gpencil_free((bGPdata *)id);
+ BKE_gpencil_free((bGPdata *)id, true);
break;
case ID_MC:
BKE_movieclip_free((MovieClip *)id);
@@ -812,6 +814,9 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
case ID_PC:
BKE_paint_curve_free((PaintCurve *)id);
break;
+ case ID_CF:
+ BKE_cachefile_free((CacheFile *)id);
+ break;
}
/* avoid notifying on removed data */
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 1aff5d502f8..430935a5fad 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -218,10 +218,7 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *l
for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next)
BKE_linestyle_geometry_modifier_copy(new_linestyle, m);
- if (ID_IS_LINKED_DATABLOCK(linestyle)) {
- BKE_id_expand_local(&new_linestyle->id);
- BKE_id_lib_local_paths(bmain, linestyle->id.lib, &new_linestyle->id);
- }
+ BKE_id_copy_ensure_local(bmain, &linestyle->id, &new_linestyle->id);
return new_linestyle;
}
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 014461e0d22..21023d9f53c 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -853,10 +853,7 @@ Mask *BKE_mask_copy(Main *bmain, Mask *mask)
/* enable fake user by default */
id_fake_user_set(&mask->id);
- if (ID_IS_LINKED_DATABLOCK(mask)) {
- BKE_id_expand_local(&mask_new->id);
- BKE_id_lib_local_paths(bmain, mask->id.lib, &mask_new->id);
- }
+ BKE_id_copy_ensure_local(bmain, &mask->id, &mask_new->id);
return mask_new;
}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 62aba1af694..470108545b8 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -247,10 +247,7 @@ Material *BKE_material_copy(Main *bmain, Material *ma)
BLI_listbase_clear(&man->gpumaterial);
- if (ID_IS_LINKED_DATABLOCK(ma)) {
- BKE_id_expand_local(&man->id);
- BKE_id_lib_local_paths(bmain, ma->id.lib, &man->id);
- }
+ BKE_id_copy_ensure_local(bmain, &ma->id, &man->id);
return man;
}
@@ -745,17 +742,18 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type)
if (mao)
id_us_min(&mao->id);
ob->mat[act - 1] = ma;
+ test_object_materials(ob, ob->data);
}
else { /* in data */
mao = (*matarar)[act - 1];
if (mao)
id_us_min(&mao->id);
(*matarar)[act - 1] = ma;
+ test_all_objects_materials(G.main, ob->data); /* Data may be used by several objects... */
}
if (ma)
id_us_plus(&ma->id);
- test_object_materials(ob, ob->data);
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 7e363e5600f..8d024ea9aa5 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -119,10 +119,7 @@ MetaBall *BKE_mball_copy(Main *bmain, MetaBall *mb)
mbn->editelems = NULL;
mbn->lastelem = NULL;
- if (ID_IS_LINKED_DATABLOCK(mb)) {
- BKE_id_expand_local(&mbn->id);
- BKE_id_lib_local_paths(bmain, mb->id.lib, &mbn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &mb->id, &mbn->id);
return mbn;
}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 2b35cdc9d64..733e9030056 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -531,10 +531,7 @@ Mesh *BKE_mesh_copy(Main *bmain, Mesh *me)
men->key->from = (ID *)men;
}
- if (ID_IS_LINKED_DATABLOCK(me)) {
- BKE_id_expand_local(&men->id);
- BKE_id_lib_local_paths(bmain, me->id.lib, &men->id);
- }
+ BKE_id_copy_ensure_local(bmain, &me->id, &men->id);
return men;
}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 1c86fbcfe8e..fa113ef5eef 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -434,7 +434,7 @@ MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
}
/* This threshold is a bit touchy (usual float precision issue), this value seems OK. */
-#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-6f)
+#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f)
/* Should only be called once.
* Beware, this modifies ref_vec and other_vec in place!
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index 1a20300457f..8562988b5e1 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -934,6 +934,7 @@ static bool mesh_check_island_boundary_uv(
}
else {
BLI_assert(loops[edge_to_loops->indices[i]].v == v2);
+ UNUSED_VARS_NDEBUG(v2);
if (!equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i]].uv) ||
!equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i + 1]].uv))
{
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index f99457a4c26..0d362086134 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -1491,6 +1491,32 @@ void BKE_movieclip_free(MovieClip *clip)
BKE_tracking_free(&clip->tracking);
}
+MovieClip *BKE_movieclip_copy(Main *bmain, MovieClip *clip)
+{
+ MovieClip *clip_new;
+
+ clip_new = BKE_libblock_copy(bmain, &clip->id);
+
+ clip_new->anim = NULL;
+ clip_new->cache = NULL;
+
+ BKE_tracking_copy(&clip_new->tracking, &clip->tracking);
+ clip_new->tracking_context = NULL;
+
+ id_us_plus((ID *)clip_new->gpd);
+
+ BKE_color_managed_colorspace_settings_copy(&clip_new->colorspace_settings, &clip->colorspace_settings);
+
+ BKE_id_copy_ensure_local(bmain, &clip->id, &clip_new->id);
+
+ return clip_new;
+}
+
+void BKE_movieclip_make_local(Main *bmain, MovieClip *clip, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &clip->id, true, lib_local);
+}
+
float BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, float framenr)
{
return framenr - (float) clip->start_frame + 1.0f;
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index d360356aa3d..87de7d589b7 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -1300,10 +1300,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski
/* node tree will generate its own interface type */
newtree->interface_type = NULL;
- if (ID_IS_LINKED_DATABLOCK(ntree)) {
- BKE_id_expand_local(&newtree->id);
- BKE_id_lib_local_paths(bmain, ntree->id.lib, &newtree->id);
- }
+ BKE_id_copy_ensure_local(bmain, &ntree->id, &newtree->id);
return newtree;
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 9c48fdfbf08..d736a455163 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1169,10 +1169,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
/* Copy runtime surve data. */
obn->curve_cache = NULL;
- if (ID_IS_LINKED_DATABLOCK(ob)) {
- BKE_id_expand_local(&obn->id);
- BKE_id_lib_local_paths(bmain, ob->id.lib, &obn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &ob->id, &obn->id);
/* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */
obn->preview = NULL;
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index cd457c77f89..fbe542ddbb5 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -83,7 +83,6 @@ typedef struct DupliContext {
int persistent_id[MAX_DUPLI_RECUR];
int level;
- int index;
const struct DupliGenerator *gen;
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 8c1502643c5..53675f33a69 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -314,6 +314,26 @@ PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name)
return pc;
}
+PaintCurve *BKE_paint_curve_copy(Main *bmain, PaintCurve *pc)
+{
+ PaintCurve *pc_new;
+
+ pc_new = BKE_libblock_copy(bmain, &pc->id);
+
+ if (pc->tot_points != 0) {
+ pc_new->points = MEM_dupallocN(pc->points);
+ }
+
+ BKE_id_copy_ensure_local(bmain, &pc->id, &pc_new->id);
+
+ return pc_new;
+}
+
+void BKE_paint_curve_make_local(Main *bmain, PaintCurve *pc, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &pc->id, true, lib_local);
+}
+
Palette *BKE_paint_palette(Paint *p)
{
return p ? p->palette : NULL;
@@ -376,6 +396,24 @@ Palette *BKE_palette_add(Main *bmain, const char *name)
return palette;
}
+Palette *BKE_palette_copy(Main *bmain, Palette *palette)
+{
+ Palette *palette_new;
+
+ palette_new = BKE_libblock_copy(bmain, &palette->id);
+
+ BLI_duplicatelist(&palette_new->colors, &palette->colors);
+
+ BKE_id_copy_ensure_local(bmain, &palette->id, &palette_new->id);
+
+ return palette_new;
+}
+
+void BKE_palette_make_local(Main *bmain, Palette *palette, bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &palette->id, true, lib_local);
+}
+
/** Free (or release) any data used by this palette (does not free the palette itself). */
void BKE_palette_free(Palette *palette)
{
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 2c0f183d78f..5a44f480de4 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -3335,10 +3335,7 @@ ParticleSettings *BKE_particlesettings_copy(Main *bmain, ParticleSettings *part)
BLI_duplicatelist(&partn->dupliweights, &part->dupliweights);
- if (ID_IS_LINKED_DATABLOCK(part)) {
- BKE_id_expand_local(&partn->id);
- BKE_id_lib_local_paths(bmain, part->id.lib, &partn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &part->id, &partn->id);
return partn;
}
@@ -4053,13 +4050,16 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
uv[0] = uv[1] = 0.f;
+ /* Grid distribution doesn't support UV or emit from vertex mode */
+ bool is_grid = (part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT);
+
if (cpa) {
if ((part->childtype == PART_CHILD_FACES) && (psmd->dm_final != NULL)) {
CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final);
const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
- if (mtface) {
+ if (mtface && !is_grid) {
mface = psmd->dm_final->getTessFaceData(psmd->dm_final, cpa->num, CD_MFACE);
mtface += cpa->num;
psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
@@ -4073,7 +4073,7 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
}
}
- if ((part->from == PART_FROM_FACE) && (psmd->dm_final != NULL)) {
+ if ((part->from == PART_FROM_FACE) && (psmd->dm_final != NULL) && !is_grid) {
CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final);
const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index d89eac327d5..4768e00f75e 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -2183,7 +2183,6 @@ static void basic_rotate(ParticleSettings *part, ParticleData *pa, float dfra, f
* http://en.wikipedia.org/wiki/Newton's_method
*
************************************************/
-#define COLLISION_MAX_COLLISIONS 10
#define COLLISION_MIN_RADIUS 0.001f
#define COLLISION_MIN_DISTANCE 0.0001f
#define COLLISION_ZERO 0.00001f
@@ -2570,10 +2569,6 @@ void BKE_psys_collision_neartest_cb(void *userdata, int index, const BVHTreeRay
pce.inside = 0;
pce.index = index;
- /* don't collide with same face again */
- if (col->hit == col->current && col->pce.index == index && col->pce.tot == 3)
- return;
-
collision = collision_sphere_to_tri(col, ray->radius, &pce, &t);
if (col->pce.inside == 0) {
collision += collision_sphere_to_edges(col, ray->radius, &pce, &t);
@@ -2609,8 +2604,17 @@ static int collision_detect(ParticleData *pa, ParticleCollision *col, BVHTreeRay
hit->dist = col->original_ray_length = 0.000001f;
for (coll = colliders->first; coll; coll=coll->next) {
- /* for boids: don't check with current ground object */
- if (coll->ob == col->skip)
+ /* for boids: don't check with current ground object; also skip if permeated */
+ bool skip = false;
+
+ for (int i = 0; i < col->skip_count; i++) {
+ if (coll->ob == col->skip[i]) {
+ skip = true;
+ break;
+ }
+ }
+
+ if (skip)
continue;
/* particles should not collide with emitter at birth */
@@ -2746,7 +2750,7 @@ static int collision_response(ParticleData *pa, ParticleCollision *col, BVHTreeR
if (through==0 && ((vc_dot>0.0f && v0_dot>0.0f && vc_dot>v0_dot) || (vc_dot<0.0f && v0_dot<0.0f && vc_dot<v0_dot)))
mul_v3_v3fl(v0_nor, pce->nor, vc_dot);
else if (v0_dot > 0.f)
- mul_v3_v3fl(v0_nor, pce->nor, vc_dot + (through ? -1.0f : 1.0f) * v0_dot);
+ mul_v3_v3fl(v0_nor, pce->nor, vc_dot + v0_dot);
else
mul_v3_v3fl(v0_nor, pce->nor, vc_dot + (through ? 1.0f : -1.0f) * v0_dot);
@@ -2801,8 +2805,10 @@ static int collision_response(ParticleData *pa, ParticleCollision *col, BVHTreeR
col->f = f;
}
- col->prev = col->hit;
- col->prev_index = hit->index;
+ /* if permeability random roll succeeded, disable collider for this sim step */
+ if (through) {
+ col->skip[col->skip_count++] = col->hit;
+ }
return 1;
}
@@ -2863,16 +2869,16 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
if (part->phystype == PART_PHYS_BOIDS && part->boids->options & BOID_ALLOW_LAND) {
col.boid = 1;
col.boid_z = pa->state.co[2];
- col.skip = pa->boid->ground;
+ col.skip[col.skip_count++] = pa->boid->ground;
}
/* 10 iterations to catch multiple collisions */
- while (collision_count < COLLISION_MAX_COLLISIONS) {
+ while (collision_count < PARTICLE_COLLISION_MAX_COLLISIONS) {
if (collision_detect(pa, &col, &hit, sim->colliders)) {
collision_count++;
- if (collision_count == COLLISION_MAX_COLLISIONS)
+ if (collision_count == PARTICLE_COLLISION_MAX_COLLISIONS)
collision_fail(pa, &col);
else if (collision_response(pa, &col, &hit, part->flag & PART_DIE_ON_COL, part->flag & PART_ROT_DYN)==0)
return;
@@ -3311,7 +3317,7 @@ static float get_base_time_step(ParticleSettings *part)
return 1.0f / (float) (part->subframes + 1);
}
/* Update time step size to suit current conditions. */
-static float update_timestep(ParticleSystem *psys, ParticleSimulationData *sim, float t_frac)
+static void update_timestep(ParticleSystem *psys, ParticleSimulationData *sim)
{
float dt_target;
if (sim->courant_num == 0.0f)
@@ -3331,7 +3337,10 @@ static float update_timestep(ParticleSystem *psys, ParticleSimulationData *sim,
psys->dt_frac = interpf(dt_target, psys->dt_frac, TIMESTEP_EXPANSION_FACTOR);
else
psys->dt_frac = dt_target;
+}
+static float sync_timestep(ParticleSystem *psys, float t_frac)
+{
/* Sync with frame end if it's close. */
if (t_frac == 1.0f)
return psys->dt_frac;
@@ -3493,7 +3502,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
psys_update_effectors(sim);
if (part->type != PART_HAIR)
- sim->colliders = get_collider_cache(sim->scene, sim->ob, NULL);
+ sim->colliders = get_collider_cache(sim->scene, sim->ob, part->collision_group);
/* initialize physics type specific stuff */
switch (part->phystype) {
@@ -3991,7 +4000,9 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
printf("%f,%f,%f,%f\n", cfra+dframe+t_frac - 1.f, t_frac, dt_frac, sim->courant_num);
#endif
if (part->time_flag & PART_TIME_AUTOSF)
- dt_frac = update_timestep(psys, sim, t_frac);
+ update_timestep(psys, sim);
+ /* Even without AUTOSF dt_frac may not add up to 1.0 due to float precision. */
+ dt_frac = sync_timestep(psys, t_frac);
}
}
}
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index e0a3e9743db..69a98c06000 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -386,9 +386,9 @@ static void ptcache_particle_interpolate(int index, void *psys_v, void **data, f
}
}
- /* determine rotation from velocity */
+ /* default to no rotation */
if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) {
- vec_to_quat(keys[2].rot, keys[2].vel, OB_NEGX, OB_POSZ);
+ unit_qt(keys[2].rot);
}
if (cfra > pa->time)
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 3e37ee83cea..c3c23756b70 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -49,6 +49,7 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
@@ -64,6 +65,7 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_cachefile.h"
#include "BKE_colortools.h"
#include "BKE_depsgraph.h"
#include "BKE_editmesh.h"
@@ -286,6 +288,13 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
ts->imapaint.paintcursor = NULL;
id_us_plus((ID *)ts->imapaint.stencil);
ts->particle.paintcursor = NULL;
+ /* duplicate Grease Pencil Drawing Brushes */
+ BLI_listbase_clear(&ts->gp_brushes);
+ for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
+ bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush);
+ BLI_addtail(&ts->gp_brushes, newbrush);
+ }
+
}
/* make a private copy of the avicodecdata */
@@ -334,7 +343,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
/* grease pencil */
if (scen->gpd) {
if (type == SCE_COPY_FULL) {
- scen->gpd = gpencil_data_duplicate(bmain, scen->gpd, false);
+ scen->gpd = BKE_gpencil_data_duplicate(bmain, scen->gpd, false);
}
else if (type == SCE_COPY_EMPTY) {
scen->gpd = NULL;
@@ -432,6 +441,10 @@ void BKE_scene_free(Scene *sce)
BKE_paint_free(&sce->toolsettings->uvsculpt->paint);
MEM_freeN(sce->toolsettings->uvsculpt);
}
+ /* free Grease Pencil Drawing Brushes */
+ BKE_gpencil_free_brushes(&sce->toolsettings->gp_brushes);
+ BLI_freelistN(&sce->toolsettings->gp_brushes);
+
BKE_paint_free(&sce->toolsettings->imapaint.paint);
MEM_freeN(sce->toolsettings);
@@ -764,6 +777,11 @@ void BKE_scene_init(Scene *sce)
gp_brush->strength = 0.5f;
gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ 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 = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
gp_brush->size = 50;
gp_brush->strength = 0.3f;
@@ -1909,6 +1927,9 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
BKE_mask_evaluate_all_masks(bmain, ctime, true);
+ /* Update animated cache files for modifiers. */
+ BKE_cachefile_update_frame(bmain, sce, ctime, (((double)sce->r.frs_sec) / (double)sce->r.frs_sec_base));
+
#ifdef POSE_ANIMATION_WORKAROUND
scene_armature_depsgraph_workaround(bmain);
#endif
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 6067a8b2d9b..c240aa27343 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -1656,6 +1656,9 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render
else if ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE)) {
BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
}
+ else if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
+ BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ }
else if (sanim && sanim->anim && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR)) {
char fname[FILE_MAXFILE];
BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
@@ -1675,13 +1678,21 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render
if (view_id > 0)
BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id);
- if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE && sanim && sanim->anim &&
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE &&
ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE)
{
- BLI_join_dirfile(name, PROXY_MAXFILE,
- dir, proxy->file);
- BLI_path_abs(name, G.main->name);
- BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", name, suffix);
+ char fname[FILE_MAXFILE];
+ BLI_join_dirfile(fname, PROXY_MAXFILE, dir, proxy->file);
+ BLI_path_abs(fname, G.main->name);
+ if (suffix[0] != '\0') {
+ /* TODO(sergey): This will actually append suffix after extension
+ * which is weird but how was originally coded in multiview branch.
+ */
+ BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", fname, suffix);
+ }
+ else {
+ BLI_strncpy(name, fname, PROXY_MAXFILE);
+ }
return true;
}
@@ -5595,3 +5606,31 @@ int BKE_sequencer_find_next_prev_edit(
return best_frame;
}
+
+static void sequencer_all_free_anim_ibufs(ListBase *seqbase, int cfra)
+{
+ for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
+ if (seq->enddisp < cfra || seq->startdisp > cfra) {
+ BKE_sequence_free_anim(seq);
+ }
+ if (seq->type == SEQ_TYPE_META) {
+ sequencer_all_free_anim_ibufs(&seq->seqbase, cfra);
+ }
+ }
+}
+
+void BKE_sequencer_all_free_anim_ibufs(int cfra)
+{
+ BKE_sequencer_cache_cleanup();
+ for (Scene *scene = G.main->scene.first;
+ scene != NULL;
+ scene = scene->id.next)
+ {
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ if (ed == NULL) {
+ /* Ignore scenes without sequencer. */
+ continue;
+ }
+ sequencer_all_free_anim_ibufs(&ed->seqbase, cfra);
+ }
+}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 799cdeeb3d0..72f058bff34 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -707,6 +707,7 @@ typedef struct ObstaclesFromDMData {
bool has_velocity;
float *vert_vel;
float *velocityX, *velocityY, *velocityZ;
+ int *num_obstacles;
} ObstaclesFromDMData;
static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
@@ -755,8 +756,10 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
/* tag obstacle cells */
data->obstacle_map[index] = 1;
- if (data->has_velocity)
+ if (data->has_velocity) {
data->obstacle_map[index] |= 8;
+ data->num_obstacles[index]++;
+ }
}
}
}
@@ -764,7 +767,7 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
static void obstacles_from_derivedmesh(
Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs,
- unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, float dt)
+ unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, int *num_obstacles, float dt)
{
if (!scs->dm) return;
{
@@ -835,7 +838,8 @@ static void obstacles_from_derivedmesh(
.sds = sds, .mvert = mvert, .mloop = mloop, .looptri = looptri,
.tree = &treeData, .obstacle_map = obstacle_map,
.has_velocity = has_velocity, .vert_vel = vert_vel,
- .velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ
+ .velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ,
+ .num_obstacles = num_obstacles
};
BLI_task_parallel_range(
sds->res_min[2], sds->res_max[2], &data, obstacles_from_derivedmesh_task_cb, true);
@@ -871,6 +875,8 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
float *b = smoke_get_color_b(sds->fluid);
unsigned int z;
+ int *num_obstacles = MEM_callocN(sizeof(int) * sds->res[0] * sds->res[1] * sds->res[2], "smoke_num_obstacles");
+
smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz);
// TODO: delete old obstacle flags
@@ -900,7 +906,7 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll)
{
SmokeCollSettings *scs = smd2->coll;
- obstacles_from_derivedmesh(collob, sds, scs, obstacles, velx, vely, velz, dt);
+ obstacles_from_derivedmesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt);
}
}
@@ -926,7 +932,15 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
b[z] = 0;
}
}
+ /* average velocities from multiple obstacles in one cell */
+ if (num_obstacles[z]) {
+ velx[z] /= num_obstacles[z];
+ vely[z] /= num_obstacles[z];
+ velz[z] /= num_obstacles[z];
+ }
}
+
+ MEM_freeN(num_obstacles);
}
/**********************************************************
@@ -2772,8 +2786,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
// create shadows before writing cache so they get stored
smoke_calc_transparency(sds, scene);
- if (sds->wt)
- {
+ if (sds->wt && sds->total_cells > 1) {
smoke_turbulence_step(sds->wt, sds->fluid);
}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index d1c7b240b94..7f5c8af2686 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -63,6 +63,7 @@ variables on the UI for now
#include "DNA_curve_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_group_types.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -496,59 +497,98 @@ static void ccd_mesh_free(ccd_Mesh *ccdm)
}
}
-static void ccd_build_deflector_hash(Scene *scene, Object *vertexowner, GHash *hash)
+static void ccd_build_deflector_hash_single(GHash *hash, Object *ob)
+{
+ /* only with deflecting set */
+ if (ob->pd && ob->pd->deflect) {
+ void **val_p;
+ if (!BLI_ghash_ensure_p(hash, ob, &val_p)) {
+ ccd_Mesh *ccdmesh = ccd_mesh_make(ob);
+ *val_p = ccdmesh;
+ }
+ }
+}
+
+/**
+ * \note group overrides scene when not NULL.
+ */
+static void ccd_build_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash)
{
- Base *base= scene->base.first;
Object *ob;
if (!hash) return;
- while (base) {
- /*Only proceed for mesh object in same layer */
- if (base->object->type==OB_MESH && (base->lay & vertexowner->lay)) {
- ob= base->object;
- if ((vertexowner) && (ob == vertexowner)) {
- /* if vertexowner is given we don't want to check collision with owner object */
- base = base->next;
+
+ if (group) {
+ /* Explicit collision group */
+ for (GroupObject *go = group->gobject.first; go; go = go->next) {
+ ob = go->ob;
+
+ if (ob == vertexowner || ob->type != OB_MESH)
continue;
- }
- /*+++ only with deflecting set */
- if (ob->pd && ob->pd->deflect && BLI_ghash_lookup(hash, ob) == NULL) {
- ccd_Mesh *ccdmesh = ccd_mesh_make(ob);
- BLI_ghash_insert(hash, ob, ccdmesh);
- }/*--- only with deflecting set */
+ ccd_build_deflector_hash_single(hash, ob);
+ }
+ }
+ else {
+ for (Base *base = scene->base.first; base; base = base->next) {
+ /*Only proceed for mesh object in same layer */
+ if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) {
+ ob= base->object;
+ if ((vertexowner) && (ob == vertexowner)) {
+ /* if vertexowner is given we don't want to check collision with owner object */
+ continue;
+ }
+
+ ccd_build_deflector_hash_single(hash, ob);
+ }
+ }
+ }
+}
- }/* mesh && layer*/
- base = base->next;
- } /* while (base) */
+static void ccd_update_deflector_hash_single(GHash *hash, Object *ob)
+{
+ if (ob->pd && ob->pd->deflect) {
+ ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash, ob);
+ if (ccdmesh) {
+ ccd_mesh_update(ob, ccdmesh);
+ }
+ }
}
-static void ccd_update_deflector_hash(Scene *scene, Object *vertexowner, GHash *hash)
+/**
+ * \note group overrides scene when not NULL.
+ */
+static void ccd_update_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash)
{
- Base *base= scene->base.first;
Object *ob;
if ((!hash) || (!vertexowner)) return;
- while (base) {
- /*Only proceed for mesh object in same layer */
- if (base->object->type==OB_MESH && (base->lay & vertexowner->lay)) {
- ob= base->object;
- if (ob == vertexowner) {
- /* if vertexowner is given we don't want to check collision with owner object */
- base = base->next;
+
+ if (group) {
+ /* Explicit collision group */
+ for (GroupObject *go = group->gobject.first; go; go = go->next) {
+ ob = go->ob;
+
+ if (ob == vertexowner || ob->type != OB_MESH)
continue;
- }
- /*+++ only with deflecting set */
- if (ob->pd && ob->pd->deflect) {
- ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash, ob);
- if (ccdmesh)
- ccd_mesh_update(ob, ccdmesh);
- }/*--- only with deflecting set */
+ ccd_update_deflector_hash_single(hash, ob);
+ }
+ }
+ else {
+ for (Base *base = scene->base.first; base; base = base->next) {
+ /*Only proceed for mesh object in same layer */
+ if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) {
+ ob= base->object;
+ if (ob == vertexowner) {
+ /* if vertexowner is given we don't want to check collision with owner object */
+ continue;
+ }
- }/* mesh && layer*/
- base = base->next;
- } /* while (base) */
+ ccd_update_deflector_hash_single(hash, ob);
+ }
+ }
+ }
}
@@ -934,22 +974,32 @@ static void free_softbody_intern(SoftBody *sb)
/* +++ dependency information functions*/
-static int are_there_deflectors(Scene *scene, unsigned int layer)
+/**
+ * \note group overrides scene when not NULL.
+ */
+static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer)
{
- Base *base;
-
- for (base = scene->base.first; base; base= base->next) {
- if ( (base->lay & layer) && base->object->pd) {
- if (base->object->pd->deflect)
+ if (group) {
+ for (GroupObject *go = group->gobject.first; go; go = go->next) {
+ if (go->ob->pd && go->ob->pd->deflect)
return 1;
}
}
+ else {
+ for (Base *base = scene->base.first; base; base= base->next) {
+ if ( (base->lay & layer) && base->object->pd) {
+ if (base->object->pd->deflect)
+ return 1;
+ }
+ }
+ }
+
return 0;
}
-static int query_external_colliders(Scene *scene, Object *me)
+static int query_external_colliders(Scene *scene, Group *group, Object *me)
{
- return(are_there_deflectors(scene, me->lay));
+ return(are_there_deflectors(scene, group, me->lay));
}
/* --- dependency information functions*/
@@ -2197,7 +2247,7 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
/* gravity = sb->grav * sb_grav_force_scale(ob); */ /* UNUSED */
/* check conditions for various options */
- do_deflector= query_external_colliders(scene, ob);
+ do_deflector= query_external_colliders(scene, sb->collision_group, ob);
/* do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); */ /* UNUSED */
do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL);
do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES));
@@ -2261,7 +2311,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
}
/* check conditions for various options */
- do_deflector= query_external_colliders(scene, ob);
+ do_deflector= query_external_colliders(scene, sb->collision_group, ob);
do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF));
do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL);
do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES));
@@ -3472,11 +3522,11 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
*/
if (dtime < 0 || dtime > 10.5f) return;
- ccd_update_deflector_hash(scene, ob, sb->scratch->colliderhash);
+ ccd_update_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash);
if (sb->scratch->needstobuildcollider) {
- if (query_external_colliders(scene, ob)) {
- ccd_build_deflector_hash(scene, ob, sb->scratch->colliderhash);
+ if (query_external_colliders(scene, sb->collision_group, ob)) {
+ ccd_build_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash);
}
sb->scratch->needstobuildcollider=0;
}
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index 80ee6d50d7e..ee6886e3fb2 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -77,10 +77,7 @@ Speaker *BKE_speaker_copy(Main *bmain, Speaker *spk)
if (spkn->sound)
id_us_plus(&spkn->sound->id);
- if (ID_IS_LINKED_DATABLOCK(spk)) {
- BKE_id_expand_local(&spkn->id);
- BKE_id_lib_local_paths(G.main, spk->id.lib, &spkn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &spk->id, &spkn->id);
return spkn;
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 10a0a39fcdd..e876bf43809 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -2699,6 +2699,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
num_draw_patches);
}
}
+ glShadeModel(GL_SMOOTH);
return;
}
#endif
@@ -2805,6 +2806,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
num_draw_patches);
}
}
+ glShadeModel(GL_SMOOTH);
return;
}
#endif
@@ -3214,6 +3216,7 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
setMaterial(userData, new_matnr, &gattribs);
ccgSubSurf_drawGLMesh(ss, true, -1, -1);
+ glShadeModel(GL_SMOOTH);
return;
}
#endif
@@ -3424,15 +3427,18 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
int current_patch = 0;
int mat_nr = -1;
int start_draw_patch = 0, num_draw_patches = 0;
+ bool draw_smooth = false;
for (i = 0; i < num_base_faces; ++i) {
const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
const int num_patches = (num_face_verts == 4) ? face_patches
: num_face_verts * grid_patches;
if (faceFlags) {
- mat_nr = faceFlags[i].mat_nr + 1;
+ mat_nr = faceFlags[i].mat_nr;
+ draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
}
else {
mat_nr = 0;
+ draw_smooth = false;
}
if (drawParams != NULL) {
@@ -3447,8 +3453,13 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == num_base_faces - 1);
+ const int next_face = min_ii(i + 1, num_base_faces - 1);
if (!flush && compareDrawOptions) {
- flush |= compareDrawOptions(userData, i, min_ii(i + 1, num_base_faces - 1)) == 0;
+ flush |= compareDrawOptions(userData, i, next_face) == 0;
+ }
+ if (!flush && faceFlags) {
+ bool new_draw_smooth = (faceFlags[next_face].flag & ME_SMOOTH);
+ flush |= (new_draw_smooth != draw_smooth);
}
current_patch += num_patches;
@@ -3458,6 +3469,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
num_draw_patches += num_patches;
}
if (num_draw_patches != 0) {
+ glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
ccgSubSurf_drawGLMesh(ss,
true,
start_draw_patch,
@@ -3470,6 +3482,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
num_draw_patches += num_patches;
}
}
+ glShadeModel(GL_SMOOTH);
return;
}
#endif
@@ -3669,6 +3682,7 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
ccgSubSurf_drawGLMesh(ss, true, -1, -1);
}
+ glShadeModel(GL_SMOOTH);
return;
}
#endif
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 82c3132d73e..1636042f479 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -491,10 +491,7 @@ Text *BKE_text_copy(Main *bmain, Text *ta)
init_undo_text(tan);
- if (ID_IS_LINKED_DATABLOCK(ta)) {
- BKE_id_expand_local(&tan->id);
- BKE_id_lib_local_paths(bmain, ta->id.lib, &tan->id);
- }
+ BKE_id_copy_ensure_local(bmain, &ta->id, &tan->id);
return tan;
}
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 8ef950294b8..94a955be801 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -876,10 +876,7 @@ Tex *BKE_texture_copy(Main *bmain, Tex *tex)
BKE_previewimg_id_copy(&texn->id, &tex->id);
- if (ID_IS_LINKED_DATABLOCK(tex)) {
- BKE_id_expand_local(&texn->id);
- BKE_id_lib_local_paths(bmain, tex->id.lib, &texn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &tex->id, &texn->id);
return texn;
}
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 3b76e456ff7..a56fc0f9abe 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -44,6 +44,7 @@
#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_math_base.h"
#include "BLI_listbase.h"
@@ -55,6 +56,7 @@
#include "BKE_fcurve.h"
#include "BKE_tracking.h"
+#include "BKE_library.h"
#include "BKE_movieclip.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -186,6 +188,133 @@ void BKE_tracking_free(MovieTracking *tracking)
tracking_dopesheet_free(&tracking->dopesheet);
}
+/* Copy the whole list of tracks. */
+static void tracking_tracks_copy(ListBase *tracks_dst, ListBase *tracks_src, GHash *tracks_mapping)
+{
+ MovieTrackingTrack *track_dst, *track_src;
+
+ BLI_listbase_clear(tracks_dst);
+ BLI_ghash_clear(tracks_mapping, NULL, NULL);
+
+ for (track_src = tracks_src->first; track_src != NULL; track_src = track_src->next) {
+ track_dst = MEM_dupallocN(track_src);
+ if (track_src->markers) {
+ track_dst->markers = MEM_dupallocN(track_src->markers);
+ }
+ id_us_plus(&track_dst->gpd->id);
+ BLI_addtail(tracks_dst, track_dst);
+ BLI_ghash_insert(tracks_mapping, track_src, track_dst);
+ }
+}
+
+/* copy the whole list of plane tracks (need whole MovieTracking structures due to embedded pointers to tracks).
+ * WARNING: implies tracking_[dst/src] and their tracks have already been copied. */
+static void tracking_plane_tracks_copy(ListBase *plane_tracks_dst, ListBase *plane_tracks_src, GHash *tracks_mapping)
+{
+ MovieTrackingPlaneTrack *plane_track_dst, *plane_track_src;
+
+ BLI_listbase_clear(plane_tracks_dst);
+
+ for (plane_track_src = plane_tracks_src->first; plane_track_src != NULL; plane_track_src = plane_track_src->next) {
+ plane_track_dst = MEM_dupallocN(plane_tracks_src);
+ if (plane_track_src->markers) {
+ plane_track_dst->markers = MEM_dupallocN(plane_track_src->markers);
+ }
+ plane_track_dst->point_tracks = MEM_mallocN(sizeof(*plane_track_dst->point_tracks) * plane_track_dst->point_tracksnr, __func__);
+ for (int i = 0; i < plane_track_dst->point_tracksnr; i++) {
+ plane_track_dst->point_tracks[i] = BLI_ghash_lookup(tracks_mapping, plane_track_src->point_tracks[i]);
+ }
+ id_us_plus(&plane_track_dst->image->id);
+ BLI_addtail(plane_tracks_dst, plane_track_dst);
+ }
+}
+
+/* Copy reconstruction structure. */
+static void tracking_reconstruction_copy(
+ MovieTrackingReconstruction *reconstruction_dst, MovieTrackingReconstruction *reconstruction_src)
+{
+ *reconstruction_dst = *reconstruction_src;
+ if (reconstruction_src->cameras) {
+ reconstruction_dst->cameras = MEM_dupallocN(reconstruction_src->cameras);
+ }
+}
+
+/* Copy stabilization structure. */
+static void tracking_stabilization_copy(
+ MovieTrackingStabilization *stabilization_dst, MovieTrackingStabilization *stabilization_src,
+ GHash *tracks_mapping)
+{
+ *stabilization_dst = *stabilization_src;
+ if (stabilization_src->rot_track) {
+ stabilization_dst->rot_track = BLI_ghash_lookup(tracks_mapping, stabilization_src->rot_track);
+ }
+}
+
+/* Copy tracking object. */
+static void tracking_object_copy(
+ MovieTrackingObject *object_dst, MovieTrackingObject *object_src, GHash *tracks_mapping)
+{
+ *object_dst = *object_src;
+ tracking_tracks_copy(&object_dst->tracks, &object_src->tracks, tracks_mapping);
+ tracking_plane_tracks_copy(&object_dst->plane_tracks, &object_src->plane_tracks, tracks_mapping);
+ tracking_reconstruction_copy(&object_dst->reconstruction, &object_src->reconstruction);
+}
+
+/* Copy list of tracking objects. */
+static void tracking_objects_copy(ListBase *objects_dst, ListBase *objects_src, GHash *tracks_mapping)
+{
+ MovieTrackingObject *object_dst, *object_src;
+
+ BLI_listbase_clear(objects_dst);
+
+ for (object_src = objects_src->first; object_src != NULL; object_src = object_src->next) {
+ object_dst = MEM_mallocN(sizeof(*object_dst), __func__);
+ tracking_object_copy(object_dst, object_src, tracks_mapping);
+ BLI_addtail(objects_dst, object_dst);
+ }
+}
+
+/* Copy tracking structure content. */
+void BKE_tracking_copy(MovieTracking *tracking_dst, MovieTracking *tracking_src)
+{
+ GHash *tracks_mapping = BLI_ghash_ptr_new(__func__);
+
+ *tracking_dst = *tracking_src;
+
+ tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping);
+ tracking_plane_tracks_copy(&tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping);
+ tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction);
+ tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization, tracks_mapping);
+ if (tracking_src->act_track) {
+ tracking_dst->act_track = BLI_ghash_lookup(tracks_mapping, tracking_src->act_track);
+ }
+ if (tracking_src->act_plane_track) {
+ MovieTrackingPlaneTrack *plane_track_src, *plane_track_dst;
+ for (plane_track_src = tracking_src->plane_tracks.first, plane_track_dst = tracking_dst->plane_tracks.first;
+ !ELEM(NULL, plane_track_src, plane_track_dst);
+ plane_track_src = plane_track_src->next, plane_track_dst = plane_track_dst->next)
+ {
+ if (plane_track_src == tracking_src->act_plane_track) {
+ tracking_dst->act_plane_track = plane_track_dst;
+ break;
+ }
+ }
+ }
+
+ /* Warning! Will override tracks_mapping. */
+ tracking_objects_copy(&tracking_dst->objects, &tracking_src->objects, tracks_mapping);
+
+ /* Those remaining are runtime data, they will be reconstructed as needed, do not bother copying them. */
+ tracking_dst->dopesheet.ok = false;
+ BLI_listbase_clear(&tracking_dst->dopesheet.channels);
+ BLI_listbase_clear(&tracking_dst->dopesheet.coverage_segments);
+
+ tracking_dst->camera.intrinsics = NULL;
+ tracking_dst->stats = NULL;
+
+ BLI_ghash_free(tracks_mapping, NULL, NULL);
+}
+
/* Initialize motion tracking settings to default values,
* used when new movie clip datablock is creating.
*/
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 78342e9919a..de1e3187a70 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -142,10 +142,7 @@ World *BKE_world_copy(Main *bmain, World *wrld)
BLI_listbase_clear(&wrldn->gpumaterial);
- if (ID_IS_LINKED_DATABLOCK(wrld)) {
- BKE_id_expand_local(&wrldn->id);
- BKE_id_lib_local_paths(bmain, wrld->id.lib, &wrldn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &wrld->id, &wrldn->id);
return wrldn;
}
diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c
index 0a8dafc2dc1..d7fd1caa8da 100644
--- a/source/blender/blenlib/intern/BLI_heap.c
+++ b/source/blender/blenlib/intern/BLI_heap.c
@@ -55,9 +55,10 @@ struct HeapNode_Chunk {
* or we allocate past the reserved number.
*
* \note Optimize number for 64kb allocs.
+ * \note keep type in sync with tot_nodes in heap_node_alloc_chunk.
*/
#define HEAP_CHUNK_DEFAULT_NUM \
- ((MEM_SIZE_OPTIMAL((1 << 16) - sizeof(struct HeapNode_Chunk))) / sizeof(HeapNode))
+ ((unsigned int)((MEM_SIZE_OPTIMAL((1 << 16) - sizeof(struct HeapNode_Chunk))) / sizeof(HeapNode)))
struct Heap {
unsigned int size;
diff --git a/source/blender/blenlib/intern/scanfill_utils.c b/source/blender/blenlib/intern/scanfill_utils.c
index 059d5cb05a4..3b6ab99ae86 100644
--- a/source/blender/blenlib/intern/scanfill_utils.c
+++ b/source/blender/blenlib/intern/scanfill_utils.c
@@ -257,7 +257,7 @@ static bool scanfill_preprocess_self_isect(
if (UNLIKELY(e_ls == NULL)) {
/* only happens in very rare cases (entirely overlapping splines).
- * in this case se can't do much useful. but at least don't crash */
+ * in this case we can't do much useful. but at least don't crash */
continue;
}
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 479d3a15e6c..8cb9ef837b2 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -77,6 +77,13 @@ if(WITH_CODEC_FFMPEG)
add_definitions(-DWITH_FFMPEG)
endif()
+if(WITH_ALEMBIC)
+ list(APPEND INC
+ ../alembic
+ )
+ add_definitions(-DWITH_ALEMBIC)
+endif()
+
blender_add_lib(bf_blenloader "${SRC}" "${INC}" "${INC_SYS}")
# needed so writefile.c can use dna_type_offsets.h
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index c7dec460b3c..8c15940d9c9 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -59,6 +59,7 @@
#include "DNA_actuator_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_cloth_types.h"
#include "DNA_controller_types.h"
#include "DNA_constraint_types.h"
@@ -114,6 +115,7 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_brush.h"
+#include "BKE_cachefile.h"
#include "BKE_cloth.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
@@ -144,7 +146,7 @@
#include "BKE_sequencer.h"
#include "BKE_outliner_treehash.h"
#include "BKE_sound.h"
-
+#include "BKE_colortools.h"
#include "NOD_common.h"
#include "NOD_socket.h"
@@ -2691,6 +2693,36 @@ static void direct_link_animdata(FileData *fd, AnimData *adt)
adt->actstrip = newdataadr(fd, adt->actstrip);
}
+/* ************ READ CACHEFILES *************** */
+
+static void lib_link_cachefiles(FileData *fd, Main *bmain)
+{
+ CacheFile *cache_file;
+
+ /* only link ID pointers */
+ for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
+ if (cache_file->id.tag & LIB_TAG_NEED_LINK) {
+ cache_file->id.tag &= ~LIB_TAG_NEED_LINK;
+ }
+
+ BLI_listbase_clear(&cache_file->object_paths);
+ cache_file->handle = NULL;
+
+ if (cache_file->adt) {
+ lib_link_animdata(fd, &cache_file->id, cache_file->adt);
+ }
+ }
+}
+
+static void direct_link_cachefile(FileData *fd, CacheFile *cache_file)
+{
+ cache_file->handle = NULL;
+
+ /* relink animdata */
+ cache_file->adt = newdataadr(fd, cache_file->adt);
+ direct_link_animdata(fd, cache_file->adt);
+}
+
/* ************ READ MOTION PATHS *************** */
/* direct data for cache */
@@ -4034,6 +4066,7 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
part->dup_group = newlibadr(fd, part->id.lib, part->dup_group);
part->eff_group = newlibadr(fd, part->id.lib, part->eff_group);
part->bb_ob = newlibadr(fd, part->id.lib, part->bb_ob);
+ part->collision_group = newlibadr(fd, part->id.lib, part->collision_group);
lib_link_partdeflect(fd, &part->id, part->pd);
lib_link_partdeflect(fd, &part->id, part->pd2);
@@ -4885,8 +4918,11 @@ static void lib_link_object(FileData *fd, Main *main)
if (ob->pd)
lib_link_partdeflect(fd, &ob->id, ob->pd);
- if (ob->soft)
+ if (ob->soft) {
+ ob->soft->collision_group = newlibadr(fd, ob->id.lib, ob->soft->collision_group);
+
ob->soft->effector_weights->group = newlibadr(fd, ob->id.lib, ob->soft->effector_weights->group);
+ }
lib_link_particlesystems(fd, ob, &ob->id, &ob->particlesystem);
lib_link_modifiers(fd, ob);
@@ -5865,6 +5901,22 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->toolsettings->wpaint->wpaint_prev = NULL;
sce->toolsettings->wpaint->tot = 0;
}
+ /* 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);
+ }
+ }
}
if (sce->ed) {
@@ -6147,7 +6199,8 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
-
+ bGPDpalette *palette;
+
/* we must firstly have some grease-pencil data to link! */
if (gpd == NULL)
return;
@@ -6155,11 +6208,19 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
/* relink animdata */
gpd->adt = newdataadr(fd, gpd->adt);
direct_link_animdata(fd, gpd->adt);
-
+
+ /* relink palettes */
+ link_list(fd, &gpd->palettes);
+ for (palette = gpd->palettes.first; palette; palette = palette->next) {
+ link_list(fd, &palette->colors);
+ }
+
/* 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);
@@ -6172,9 +6233,12 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
gps->points = newdataadr(fd, gps->points);
/* the triangulation is not saved, so need to be recalculated */
- gps->flag |= GP_STROKE_RECALC_CACHES;
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;
}
}
}
@@ -6331,10 +6395,8 @@ static void lib_link_screen(FileData *fd, Main *main)
snode->id = newlibadr(fd, sc->id.lib, snode->id);
snode->from = newlibadr(fd, sc->id.lib, snode->from);
- if (snode->id) {
- ntree = ntreeFromID(snode->id);
- snode->nodetree = ntree ? ntree : newlibadr_us(fd, sc->id.lib, snode->nodetree);
- }
+ ntree = snode->id ? ntreeFromID(snode->id) : NULL;
+ snode->nodetree = ntree ? ntree : newlibadr_us(fd, sc->id.lib, snode->nodetree);
for (path = snode->treepath.first; path; path = path->next) {
if (path == snode->treepath.first) {
@@ -6713,11 +6775,8 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
snode->id = restore_pointer_by_name(id_map, snode->id, USER_REAL);
snode->from = restore_pointer_by_name(id_map, snode->from, USER_IGNORE);
- if (snode->id) {
- ntree = ntreeFromID(snode->id);
- snode->nodetree = ntree ? ntree :
- restore_pointer_by_name(id_map, (ID *)snode->nodetree, USER_REAL);
- }
+ ntree = snode->id ? ntreeFromID(snode->id) : NULL;
+ snode->nodetree = ntree ? ntree : restore_pointer_by_name(id_map, (ID *)snode->nodetree, USER_REAL);
for (path = snode->treepath.first; path; path = path->next) {
if (path == snode->treepath.first) {
@@ -7468,6 +7527,7 @@ static void lib_link_movieclip(FileData *fd, Main *main)
for (object = tracking->objects.first; object; object = object->next) {
lib_link_movieTracks(fd, clip, &object->tracks);
+ lib_link_moviePlaneTracks(fd, clip, &object->plane_tracks);
}
clip->id.tag &= ~LIB_TAG_NEED_LINK;
@@ -7881,6 +7941,7 @@ static const char *dataname(short id_code)
case ID_MC: return "Data from MC";
case ID_MSK: return "Data from MSK";
case ID_LS: return "Data from LS";
+ case ID_CF: return "Data from CF";
}
return "Data from Lib Block";
@@ -8132,6 +8193,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
case ID_PC:
direct_link_paint_curve(fd, (PaintCurve *)id);
break;
+ case ID_CF:
+ direct_link_cachefile(fd, (CacheFile *)id);
+ break;
}
oldnewmap_free_unused(fd->datamap);
@@ -8325,6 +8389,7 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_mask(fd, main);
lib_link_linestyle(fd, main);
lib_link_gpencil(fd, main);
+ lib_link_cachefiles(fd, main);
lib_link_mesh(fd, main); /* as last: tpage images with users at zero */
@@ -8836,6 +8901,7 @@ static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSetting
expand_doit(fd, mainvar, part->dup_group);
expand_doit(fd, mainvar, part->eff_group);
expand_doit(fd, mainvar, part->bb_ob);
+ expand_doit(fd, mainvar, part->collision_group);
if (part->adt)
expand_animdata(fd, mainvar, part->adt);
@@ -8846,6 +8912,37 @@ static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSetting
expand_doit(fd, mainvar, part->mtex[a]->object);
}
}
+
+ if (part->effector_weights) {
+ expand_doit(fd, mainvar, part->effector_weights->group);
+ }
+
+ if (part->pd) {
+ expand_doit(fd, mainvar, part->pd->tex);
+ expand_doit(fd, mainvar, part->pd->f_source);
+ }
+ if (part->pd2) {
+ expand_doit(fd, mainvar, part->pd2->tex);
+ expand_doit(fd, mainvar, part->pd2->f_source);
+ }
+
+ if (part->boids) {
+ BoidState *state;
+ BoidRule *rule;
+
+ for (state = part->boids->states.first; state; state = state->next) {
+ for (rule = state->rules.first; rule; rule = rule->next) {
+ if (rule->type == eBoidRuleType_Avoid) {
+ BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
+ expand_doit(fd, mainvar, gabr->ob);
+ }
+ else if (rule->type == eBoidRuleType_FollowLeader) {
+ BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
+ expand_doit(fd, mainvar, flbr->ob);
+ }
+ }
+ }
+ }
}
static void expand_group(FileData *fd, Main *mainvar, Group *group)
@@ -9212,7 +9309,7 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
for (psys = ob->particlesystem.first; psys; psys = psys->next)
expand_doit(fd, mainvar, psys->part);
-
+
for (sens = ob->sensors.first; sens; sens = sens->next) {
if (sens->type == SENS_MESSAGE) {
bMessageSensor *ms = sens->data;
@@ -9291,8 +9388,18 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
}
}
- if (ob->pd && ob->pd->tex)
+ if (ob->pd) {
expand_doit(fd, mainvar, ob->pd->tex);
+ expand_doit(fd, mainvar, ob->pd->f_source);
+ }
+
+ if (ob->soft) {
+ expand_doit(fd, mainvar, ob->soft->collision_group);
+
+ if (ob->soft->effector_weights) {
+ expand_doit(fd, mainvar, ob->soft->effector_weights->group);
+ }
+ }
if (ob->rigidbody_constraint) {
expand_doit(fd, mainvar, ob->rigidbody_constraint->ob1);
@@ -9392,6 +9499,13 @@ static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)
expand_animdata(fd, mainvar, ca->adt);
}
+static void expand_cachefile(FileData *fd, Main *mainvar, CacheFile *cache_file)
+{
+ if (cache_file->adt) {
+ expand_animdata(fd, mainvar, cache_file->adt);
+ }
+}
+
static void expand_speaker(FileData *fd, Main *mainvar, Speaker *spk)
{
expand_doit(fd, mainvar, spk->sound);
@@ -9587,6 +9701,9 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
case ID_GD:
expand_gpencil(fd, mainvar, (bGPdata *)id);
break;
+ case ID_CF:
+ expand_cachefile(fd, mainvar, (CacheFile *)id);
+ break;
}
do_it = true;
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index a254a854c66..af95649a559 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -63,6 +63,7 @@
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_screen.h"
+#include "BKE_gpencil.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -1075,15 +1076,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- /* init grease pencil smooth level iterations */
- for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->draw_smoothlvl == 0) {
- gpl->draw_smoothlvl = 1;
- }
- }
- }
-
for (bScreen *screen = main->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) {
@@ -1192,7 +1184,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
for (Camera *camera = main->camera.first; camera != NULL; camera = camera->id.next) {
if (camera->stereo.pole_merge_angle_from == 0.0f &&
- camera->stereo.pole_merge_angle_to == 0.0f)
+ camera->stereo.pole_merge_angle_to == 0.0f)
{
camera->stereo.pole_merge_angle_from = DEG2RADF(60.0f);
camera->stereo.pole_merge_angle_to = DEG2RADF(75.0f);
@@ -1231,5 +1223,102 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
br->flag |= BRUSH_ACCUMULATE;
}
}
+
+ if (!DNA_struct_elem_find(fd->filesdna, "ClothSimSettings", "float", "time_scale")) {
+ Object *ob;
+ ModifierData *md;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Cloth) {
+ ClothModifierData *clmd = (ClothModifierData *)md;
+ clmd->sim_parms->time_scale = 1.0f;
+ }
+ else if (md->type == eModifierType_ParticleSystem) {
+ ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
+ if (pmd->psys->clmd) {
+ pmd->psys->clmd->sim_parms->time_scale = 1.0f;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 277, 3)) {
+ /* ------- init of grease pencil initialization --------------- */
+ if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "bGPDpalettecolor", "palcolor")) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ 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) {
+ GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
+ GP_EditBrush_Data *brush;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH];
+ brush->size = 25;
+ brush->strength = 0.5f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ }
+ }
+ /* create a default grease pencil drawing brushes set */
+ if (!BLI_listbase_is_empty(&main->gpencil)) {
+ for (Scene *scene = main->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 = main->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);
+ 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);
+ if (palcolor != NULL) {
+ /* set color attributes */
+ copy_v4_v4(palcolor->color, gpl->color);
+ copy_v4_v4(palcolor->fill, gpl->fill);
+ palcolor->flag = gpl->flag;
+ /* set layer opacity to 1 */
+ gpl->opacity = 1.0f;
+ /* set tint color */
+ ARRAY_SET_ITEMS(gpl->tintcolor, 0.0f, 0.0f, 0.0f, 0.0f);
+
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* set stroke to palette and force recalculation */
+ strcpy(gps->colorname, gpl->info);
+ gps->palcolor = NULL;
+ gps->flag |= GP_STROKE_RECALC_COLOR;
+ gps->thickness = gpl->thickness;
+ /* set alpha strength to 1 */
+ for (int i = 0; i < gps->totpoints; i++) {
+ gps->points[i].strength = 1.0f;
+ }
+
+ }
+ }
+ }
+ /* 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);
+ }
+ }
+ }
+ /* ------- end of grease pencil initialization --------------- */
}
+
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 0ed7a397e0b..ec817b9b261 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -108,6 +108,11 @@ void BLO_update_defaults_startup_blend(Main *bmain)
brush->strength = 0.5f;
brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH];
+ brush->size = 25;
+ brush->strength = 0.5f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
brush->size = 50;
brush->strength = 0.3f;
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 379e52c925b..84595b2f4a0 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -107,6 +107,7 @@
#include "DNA_armature_types.h"
#include "DNA_actuator_types.h"
#include "DNA_brush_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
#include "DNA_constraint_types.h"
@@ -2668,6 +2669,20 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
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);
+ }
+ }
+
write_paint(wd, &tos->imapaint.paint);
@@ -2830,6 +2845,7 @@ static void write_gpencils(WriteData *wd, ListBase *lb)
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
+ bGPDpalette *palette;
for (gpd = lb->first; gpd; gpd = gpd->id.next) {
if (gpd->id.us > 0 || wd->current) {
@@ -2856,6 +2872,11 @@ static void write_gpencils(WriteData *wd, ListBase *lb)
}
}
}
+ /* write grease-pencil palettes */
+ writelist(wd, DATA, bGPDpalette, &gpd->palettes);
+ for (palette = gpd->palettes.first; palette; palette = palette->next) {
+ writelist(wd, DATA, bGPDpalettecolor, &palette->colors);
+ }
}
}
@@ -3857,6 +3878,21 @@ static void write_linestyles(WriteData *wd, ListBase *idbase)
}
}
+static void write_cachefiles(WriteData *wd, ListBase *idbase)
+{
+ CacheFile *cache_file;
+
+ for (cache_file = idbase->first; cache_file; cache_file = cache_file->id.next) {
+ if (cache_file->id.us > 0 || wd->current) {
+ writestruct(wd, ID_CF, CacheFile, 1, cache_file);
+
+ if (cache_file->adt) {
+ write_animdata(wd, cache_file->adt);
+ }
+ }
+ }
+}
+
/* Keep it last of write_foodata functions. */
static void write_libraries(WriteData *wd, Main *main)
{
@@ -4054,6 +4090,7 @@ static bool write_file_handle(
write_paintcurves(wd, &mainvar->paintcurves);
write_gpencils(wd, &mainvar->gpencil);
write_linestyles(wd, &mainvar->linestyle);
+ write_cachefiles(wd, &mainvar->cachefiles);
write_libraries(wd, mainvar->next);
/* So changes above don't cause a 'DNA1' to be detected as changed on undo. */
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index 3838e8c827c..1d76077c9f1 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -120,6 +120,7 @@ bool BLT_lang_is_ime_supported(void);
#define BLT_I18NCONTEXT_ID_ARMATURE "Armature"
#define BLT_I18NCONTEXT_ID_BRUSH "Brush"
#define BLT_I18NCONTEXT_ID_CAMERA "Camera"
+#define BLT_I18NCONTEXT_ID_CACHEFILE "CacheFile"
#define BLT_I18NCONTEXT_ID_CURVE "Curve"
#define BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE "FreestyleLineStyle"
#define BLT_I18NCONTEXT_ID_GPENCIL "GPencil"
@@ -171,6 +172,7 @@ typedef struct {
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_ARMATURE, "id_armature"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_BRUSH, "id_brush"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CAMERA, "id_camera"), \
+ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CACHEFILE, "id_cachefile"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CURVE, "id_curve"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, "id_fs_linestyle"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_GPENCIL, "id_gpencil"), \
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index 9b074dc4db4..b5f9575aff5 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -2065,7 +2065,7 @@ bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len)
}
/* 2) loop over non-boundary edges that use boundary verts,
- * check each have 2 tagges faces connected (faces that only use 'varr' verts) */
+ * check each have 2 tagged faces connected (faces that only use 'varr' verts) */
ok = true;
for (i = 0; i < len; i++) {
BM_ITER_ELEM (e, &fiter, varr[i], BM_EDGES_OF_VERT) {
diff --git a/source/blender/compositor/nodes/COM_FilterNode.cpp b/source/blender/compositor/nodes/COM_FilterNode.cpp
index 7493f24ba6b..e8b08ce2ce1 100644
--- a/source/blender/compositor/nodes/COM_FilterNode.cpp
+++ b/source/blender/compositor/nodes/COM_FilterNode.cpp
@@ -49,7 +49,7 @@ void FilterNode::convertToOperations(NodeConverter &converter, const CompositorC
operation->set3x3Filter(-1, -1, -1, -1, 9, -1, -1, -1, -1);
break;
case CMP_FILT_LAPLACE:
- operation = new ConvolutionFilterOperation();
+ operation = new ConvolutionEdgeFilterOperation();
operation->set3x3Filter(-1 / 8.0f, -1 / 8.0f, -1 / 8.0f, -1 / 8.0f, 1.0f, -1 / 8.0f, -1 / 8.0f, -1 / 8.0f, -1 / 8.0f);
break;
case CMP_FILT_SOBEL:
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index d1de83ec8a9..945a4785b9c 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -168,7 +168,7 @@ void DEG_evaluate_on_framechange(struct EvaluationContext *eval_ctx,
struct Main *bmain,
Depsgraph *graph,
float ctime,
- const int layer);
+ const unsigned int layer);
/* Data changed recalculation entry point.
* < context_type: context to perform evaluation for
@@ -176,7 +176,7 @@ void DEG_evaluate_on_framechange(struct EvaluationContext *eval_ctx,
*/
void DEG_evaluate_on_refresh_ex(struct EvaluationContext *eval_ctx,
Depsgraph *graph,
- const int layers);
+ const unsigned int layers);
/* Data changed recalculation entry point.
* < context_type: context to perform evaluation for
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index ce30df29e26..98ccce7e34e 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -81,6 +81,7 @@ void DEG_scene_graph_free(struct Scene *scene);
* as a symbolic reference to the current DepsNode.
* All relations will be defined in reference to that node.
*/
+struct CacheFile;
typedef enum {
DEG_COMPONENT_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
@@ -93,6 +94,7 @@ typedef enum {
DEG_COMPONENT_BONE, /* Bone Component - Child/Subcomponent of Pose */
DEG_COMPONENT_EVAL_PARTICLES, /* Particle Systems Component */
DEG_COMPONENT_SHADING, /* Material Shading Component */
+ DEG_COMPONENT_CACHE, /* Cache Component */
} eDepsComponent;
struct DepsNodeHandle
@@ -122,6 +124,10 @@ struct DepsNodeHandle
struct Image *ima,
eDepsComponent component,
const char *description);
+ void (*add_cache_relation)(struct DepsNodeHandle *handle,
+ struct CacheFile *cache_file,
+ eDepsComponent component,
+ const char *description);
};
void DEG_add_scene_relation(struct DepsNodeHandle *node,
@@ -149,6 +155,10 @@ void DEG_add_image_relation(struct DepsNodeHandle *handle,
struct Image *ima,
eDepsComponent component,
const char *description);
+void DEG_add_cache_relation(struct DepsNodeHandle *handle,
+ struct CacheFile *cache_file,
+ eDepsComponent component,
+ const char *description);
/* TODO(sergey): Remove once all geometry update is granular. */
void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short flag);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 7ca2ef05a36..42b00438d33 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -140,6 +140,7 @@ DEG::eDepsNode_Type deg_build_get_component_type(
case DEG_COMPONENT_BONE: return DEG::DEPSNODE_TYPE_BONE;
case DEG_COMPONENT_EVAL_PARTICLES: return DEG::DEPSNODE_TYPE_EVAL_PARTICLES;
case DEG_COMPONENT_SHADING: return DEG::DEPSNODE_TYPE_SHADING;
+ case DEG_COMPONENT_CACHE: return DEG::DEPSNODE_TYPE_CACHE;
}
return DEG::DEPSNODE_TYPE_UNDEFINED;
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 9c0f88a8042..71b2cc16871 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -46,6 +46,7 @@ extern "C" {
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
@@ -133,6 +134,15 @@ struct NodeBuilderHandle
handle->builder->build_image(ima);
}
+ static void add_cache_relation(DepsNodeHandle *_handle,
+ CacheFile *cache_file,
+ eDepsComponent component,
+ const char *description)
+ {
+ NodeBuilderHandle *handle = (NodeBuilderHandle *)_handle;
+ handle->builder->build_cachefile(cache_file);
+ }
+
NodeBuilderHandle(DepsgraphNodeBuilder *builder) :
builder(builder)
{
@@ -140,6 +150,7 @@ struct NodeBuilderHandle
base.add_texture_relation = add_texture_relation;
base.add_nodetree_relation = add_nodetree_relation;
base.add_image_relation = add_image_relation;
+ base.add_cache_relation = add_cache_relation;
}
DepsNodeHandle base;
@@ -374,6 +385,14 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
if (scene->gpd) {
build_gpencil(scene->gpd);
}
+
+ /* cache files */
+ for (CacheFile *cachefile = static_cast<CacheFile *>(bmain->cachefiles.first);
+ cachefile;
+ cachefile = static_cast<CacheFile *>(cachefile->id.next))
+ {
+ build_cachefile(cachefile);
+ }
}
void DepsgraphNodeBuilder::build_group(Main *bmain,
@@ -1345,4 +1364,18 @@ void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd)
build_animdata(gpd_id);
}
+void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file)
+{
+ ID *cache_file_id = &cache_file->id;
+
+ add_component_node(cache_file_id, DEPSNODE_TYPE_CACHE);
+
+ add_operation_node(cache_file_id, DEPSNODE_TYPE_CACHE,
+ DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Cache File Update");
+
+ add_id_node(cache_file_id);
+ build_animdata(cache_file_id);
+}
+
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 35ef26713fd..e61c7572327 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -33,6 +33,7 @@
#include "intern/depsgraph_types.h"
struct Base;
+struct CacheFile;
struct bGPdata;
struct ListBase;
struct GHash;
@@ -148,6 +149,7 @@ struct DepsgraphNodeBuilder {
void build_world(World *world);
void build_compositor(Scene *scene);
void build_gpencil(bGPdata *gpd);
+ void build_cachefile(CacheFile *cache_file);
protected:
Main *m_bmain;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 17d36c9645d..2e8fee7aea6 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -47,6 +47,7 @@ extern "C" {
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
#include "DNA_effect_types.h"
@@ -174,6 +175,16 @@ struct RelationBuilderHandle
handle->builder->add_node_relation(comp_key, handle->node, DEPSREL_TYPE_STANDARD, description);
}
+ static void add_cache_relation(DepsNodeHandle *_handle,
+ CacheFile *cache_file,
+ eDepsComponent component,
+ const char *description)
+ {
+ RelationBuilderHandle *handle = cast(_handle);
+ ComponentKey comp_key(&cache_file->id, deg_build_get_component_type(component));
+ handle->builder->add_node_relation(comp_key, handle->node, DEG::DEPSREL_TYPE_CACHE, description);
+ }
+
RelationBuilderHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const string &default_name = "") :
builder(builder),
node(node),
@@ -187,6 +198,7 @@ struct RelationBuilderHandle
base.add_texture_relation = add_texture_relation;
base.add_nodetree_relation = add_nodetree_relation;
base.add_image_relation = add_image_relation;
+ base.add_cache_relation = add_cache_relation;
}
DepsNodeHandle base;
@@ -683,6 +695,18 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
TimeSourceKey time_src_key;
add_relation(time_src_key, constraint_op_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
}
+ else if (cti->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) {
+ /* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint dependency chain. */
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, constraint_op_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
+
+ bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data;
+
+ if (data->cache_file) {
+ ComponentKey cache_key(&data->cache_file->id, DEPSNODE_TYPE_CACHE);
+ add_relation(cache_key, constraint_op_key, DEPSREL_TYPE_CACHE, cti->name);
+ }
+ }
else if (cti->get_constraint_targets) {
ListBase targets = {NULL, NULL};
cti->get_constraint_targets(con, &targets);
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
index 5ce84ee29db..70cd5f11a47 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
@@ -90,6 +90,7 @@ static const int deg_debug_node_type_color_map[][2] = {
{DEPSNODE_TYPE_GEOMETRY, 8},
{DEPSNODE_TYPE_SEQUENCER, 9},
{DEPSNODE_TYPE_SHADING, 10},
+ {DEPSNODE_TYPE_CACHE, 11},
{-1, 0}
};
#endif
@@ -288,7 +289,7 @@ static void deg_debug_graphviz_node_single(const DebugContext &ctx,
if (node->type == DEPSNODE_TYPE_ID_REF) {
IDDepsNode *id_node = (IDDepsNode *)node;
char buf[256];
- BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %u)", id_node->layers);
name += buf;
}
if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) {
@@ -324,7 +325,7 @@ static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
if (node->type == DEPSNODE_TYPE_ID_REF) {
IDDepsNode *id_node = (IDDepsNode *)node;
char buf[256];
- BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %u)", id_node->layers);
name += buf;
}
deg_debug_fprintf(ctx, "// %s\n", name.c_str());
@@ -401,6 +402,7 @@ static void deg_debug_graphviz_node(const DebugContext &ctx,
case DEPSNODE_TYPE_EVAL_POSE:
case DEPSNODE_TYPE_BONE:
case DEPSNODE_TYPE_SHADING:
+ case DEPSNODE_TYPE_CACHE:
case DEPSNODE_TYPE_EVAL_PARTICLES:
{
ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 213bb304d73..08b264f8497 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -191,7 +191,7 @@ struct Depsgraph {
/* Layers Visibility .................. */
/* Visible layers bitfield, used for skipping invisible objects updates. */
- int layers;
+ unsigned int layers;
// XXX: additional stuff like eval contexts, mempools for allocating nodes from, etc.
};
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 67707834076..6c4b7229a41 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
extern "C" {
+#include "DNA_cachefile_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -120,6 +121,15 @@ void DEG_add_image_relation(struct DepsNodeHandle *handle,
handle->add_image_relation(handle, ima, component, description);
}
+void DEG_add_cache_relation(struct DepsNodeHandle *handle,
+ struct CacheFile *cache_file,
+ eDepsComponent component,
+ const char *description)
+{
+ if (handle->add_cache_relation)
+ handle->add_cache_relation(handle, cache_file, component, description);
+}
+
void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index ab82421195f..2e4904e4281 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -133,7 +133,7 @@ void DEG_evaluate_on_framechange(EvaluationContext *eval_ctx,
Main *bmain,
Depsgraph *graph,
float ctime,
- const int layers)
+ const unsigned int layers)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
/* Update time on primary timesource. */
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index cac4eaae215..7f2f6a65f5e 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
extern "C" {
+#include "BKE_idcode.h"
#include "BKE_main.h"
#include "DEG_depsgraph_query.h"
@@ -42,7 +43,7 @@ extern "C" {
bool DEG_id_type_tagged(Main *bmain, short idtype)
{
- return bmain->id_tag_update[((unsigned char *)&idtype)[0]] != 0;
+ return bmain->id_tag_update[BKE_idcode_to_index(idtype)] != 0;
}
short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index ea5afaab3f7..b7b62bd59f9 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -44,6 +44,7 @@ extern "C" {
#include "BLI_task.h"
+#include "BKE_idcode.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -259,10 +260,8 @@ void DEG_id_type_tag(Main *bmain, short idtype)
DEG_id_type_tag(bmain, ID_WO);
DEG_id_type_tag(bmain, ID_SCE);
}
- /* We tag based on first ID type character to avoid
- * looping over all ID's in case there are no tags.
- */
- bmain->id_tag_update[((unsigned char *)&idtype)[0]] = 1;
+
+ bmain->id_tag_update[BKE_idcode_to_index(idtype)] = 1;
}
/* Recursively push updates out to all nodes dependent on this,
@@ -373,10 +372,7 @@ void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
ListBase *lb = lbarray[a];
ID *id = (ID *)lb->first;
- /* We tag based on first ID type character to avoid
- * looping over all ID's in case there are no tags.
- */
- if (id && bmain->id_tag_update[(unsigned char)id->name[0]]) {
+ if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
updated = true;
break;
}
@@ -401,10 +397,7 @@ void DEG_ids_clear_recalc(Main *bmain)
ListBase *lb = lbarray[a];
ID *id = (ID *)lb->first;
- /* We tag based on first ID type character to avoid
- * looping over all ID's in case there are no tags.
- */
- if (id && bmain->id_tag_update[(unsigned char)id->name[0]]) {
+ if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
for (; id; id = (ID *)id->next) {
id->tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h
index a0157190b9e..1e20bbdd142 100644
--- a/source/blender/depsgraph/intern/depsgraph_types.h
+++ b/source/blender/depsgraph/intern/depsgraph_types.h
@@ -133,6 +133,8 @@ typedef enum eDepsNode_Type {
DEPSNODE_TYPE_EVAL_PARTICLES = 23,
/* Material Shading Component */
DEPSNODE_TYPE_SHADING = 24,
+ /* Cache Component */
+ DEPSNODE_TYPE_CACHE = 25,
} eDepsNode_Type;
/* Identifiers for common operations (as an enum). */
@@ -347,6 +349,9 @@ typedef enum eDepsRelation_Type {
/* relationship is used to trigger editor/screen updates */
DEPSREL_TYPE_UPDATE_UI,
+
+ /* cache dependency */
+ DEPSREL_TYPE_CACHE,
} eDepsRelation_Type;
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index 3024d625846..c3fd202d832 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -72,13 +72,13 @@ namespace DEG {
static void schedule_children(TaskPool *pool,
Depsgraph *graph,
OperationDepsNode *node,
- const int layers,
+ const unsigned int layers,
const int thread_id);
struct DepsgraphEvalState {
EvaluationContext *eval_ctx;
Depsgraph *graph;
- int layers;
+ unsigned int layers;
};
static void deg_task_run_func(TaskPool *pool,
@@ -140,7 +140,7 @@ static void deg_task_run_func(TaskPool *pool,
OperationDepsNode *child = (OperationDepsNode *)rel->to;
BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
if (!child->scheduled) {
- int id_layers = child->owner->owner->layers;
+ unsigned int id_layers = child->owner->owner->layers;
if (!((child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
(id_layers & state->layers) != 0))
{
@@ -197,14 +197,14 @@ static void deg_task_run_func(TaskPool *pool,
typedef struct CalculatePengindData {
Depsgraph *graph;
- int layers;
+ unsigned int layers;
} CalculatePengindData;
static void calculate_pending_func(void *data_v, int i)
{
CalculatePengindData *data = (CalculatePengindData *)data_v;
Depsgraph *graph = data->graph;
- int layers = data->layers;
+ unsigned int layers = data->layers;
OperationDepsNode *node = graph->operations[i];
IDDepsNode *id_node = node->owner->owner;
@@ -231,7 +231,7 @@ static void calculate_pending_func(void *data_v, int i)
}
}
-static void calculate_pending_parents(Depsgraph *graph, int layers)
+static void calculate_pending_parents(Depsgraph *graph, unsigned int layers)
{
const int num_operations = graph->operations.size();
const bool do_threads = num_operations > 256;
@@ -276,11 +276,11 @@ static void calculate_eval_priority(OperationDepsNode *node)
* dec_parents: Decrement pending parents count, true when child nodes are
* scheduled after a task has been completed.
*/
-static void schedule_node(TaskPool *pool, Depsgraph *graph, int layers,
+static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers,
OperationDepsNode *node, bool dec_parents,
const int thread_id)
{
- int id_layers = node->owner->owner->layers;
+ unsigned int id_layers = node->owner->owner->layers;
if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
(id_layers & layers) != 0)
@@ -314,7 +314,7 @@ static void schedule_node(TaskPool *pool, Depsgraph *graph, int layers,
static void schedule_graph(TaskPool *pool,
Depsgraph *graph,
- const int layers)
+ const unsigned int layers)
{
foreach (OperationDepsNode *node, graph->operations) {
schedule_node(pool, graph, layers, node, false, 0);
@@ -324,7 +324,7 @@ static void schedule_graph(TaskPool *pool,
static void schedule_children(TaskPool *pool,
Depsgraph *graph,
OperationDepsNode *node,
- const int layers,
+ const unsigned int layers,
const int thread_id)
{
foreach (DepsRelation *rel, node->outlinks) {
@@ -352,7 +352,7 @@ static void schedule_children(TaskPool *pool,
*/
void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
Depsgraph *graph,
- const int layers)
+ const unsigned int layers)
{
/* Generate base evaluation context, upon which all the others are derived. */
// TODO: this needs both main and scene access...
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h
index 92f87b03803..49c0379939e 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval.h
@@ -47,6 +47,6 @@ struct Depsgraph;
*/
void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
Depsgraph *graph,
- const int layers);
+ const unsigned int layers);
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc
index db807d22b89..eb408f293de 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node.cc
@@ -182,7 +182,7 @@ void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
this->eval_flags = 0;
/* For object we initialize layers to layer from base. */
- if (GS(id) == ID_OB) {
+ if (GS(id->name) == ID_OB) {
this->layers = 0;
}
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h
index 416996052c9..b2262c4bd12 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node.h
@@ -176,7 +176,7 @@ struct IDDepsNode : public DepsNode {
GHash *components;
/* Layers of this node with accumulated layers of it's output relations. */
- int layers;
+ unsigned int layers;
/* Additional flags needed for scene evaluation.
* TODO(sergey): Only needed for until really granular updates
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
index 6ac45c99798..01f33b6368b 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
@@ -120,7 +120,7 @@ string ComponentDepsNode::identifier() const
sprintf(typebuf, "(%d)", type);
char layers[16];
- sprintf(layers, "%d", this->layers);
+ sprintf(layers, "%u", this->layers);
return string(typebuf) + name + " : " + idname + " (Layers: " + layers + ")";
}
@@ -366,6 +366,11 @@ static DepsNodeFactoryImpl<ParticlesComponentDepsNode> DNTI_EVAL_PARTICLES;
DEG_DEPSNODE_DEFINE(ShadingComponentDepsNode, DEPSNODE_TYPE_SHADING, "Shading Component");
static DepsNodeFactoryImpl<ShadingComponentDepsNode> DNTI_SHADING;
+/* Cache Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(CacheComponentDepsNode, DEPSNODE_TYPE_CACHE, "Cache Component");
+static DepsNodeFactoryImpl<CacheComponentDepsNode> DNTI_CACHE;
+
/* Node Types Register =================================== */
@@ -383,6 +388,8 @@ void deg_register_component_depsnodes()
deg_register_node_typeinfo(&DNTI_EVAL_PARTICLES);
deg_register_node_typeinfo(&DNTI_SHADING);
+
+ deg_register_node_typeinfo(&DNTI_CACHE);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h
index 6f62d91cd79..7dec8eaaa90 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h
@@ -159,7 +159,7 @@ struct ComponentDepsNode : public DepsNode {
// XXX: a poll() callback to check if component's first node can be started?
/* Temporary bitmask, used during graph construction. */
- int layers;
+ unsigned int layers;
};
/* ---------------------------------------- */
@@ -209,6 +209,10 @@ struct ShadingComponentDepsNode : public ComponentDepsNode {
DEG_DEPSNODE_DECLARE;
};
+struct CacheComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
void deg_register_component_depsnodes();
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index ea2f7fc5588..3085e383909 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -40,6 +40,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_camera_types.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
@@ -1578,6 +1579,88 @@ static bAnimChannelType ACF_DSTEX =
/* Camera Expander ------------------------------------------- */
// TODO: just get this from RNA?
+static int acf_dscachefile_icon(bAnimListElem *ale)
+{
+ UNUSED_VARS(ale);
+ return ICON_FILE;
+}
+
+/* get the appropriate flag(s) for the setting when it is valid */
+static int acf_dscachefile_setting_flag(bAnimContext *ac, eAnimChannel_Settings setting, bool *neg)
+{
+ /* clear extra return data first */
+ *neg = false;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return CACHEFILE_DS_EXPAND;
+
+ case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
+ return ADT_NLA_EVAL_OFF;
+
+ case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
+ *neg = true;
+ return ADT_CURVES_NOT_VISIBLE;
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return ADT_UI_SELECTED;
+
+ default: /* unsupported */
+ return 0;
+ }
+
+ UNUSED_VARS(ac);
+}
+
+/* get pointer to the setting */
+static void *acf_dscachefile_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
+{
+ CacheFile *cache_file = (CacheFile *)ale->data;
+
+ /* clear extra return data first */
+ *type = 0;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return GET_ACF_FLAG_PTR(cache_file->flag, type);
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
+ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
+ if (cache_file->adt) {
+ return GET_ACF_FLAG_PTR(cache_file->adt->flag, type);
+ }
+
+ return NULL;
+
+ default: /* unsupported */
+ return NULL;
+ }
+}
+
+/* CacheFile expander type define. */
+static bAnimChannelType ACF_DSCACHEFILE =
+{
+ "Cache File Expander", /* type name */
+ ACHANNEL_ROLE_EXPANDER, /* role */
+
+ acf_generic_dataexpand_color, /* backdrop color */
+ acf_generic_dataexpand_backdrop, /* backdrop */
+ acf_generic_indention_1, /* indent level */
+ acf_generic_basic_offset, /* offset */
+
+ acf_generic_idblock_name, /* name */
+ acf_generic_idfill_name_prop, /* name prop */
+ acf_dscachefile_icon, /* icon */
+
+ acf_generic_dataexpand_setting_valid, /* has setting */
+ acf_dscachefile_setting_flag, /* flag for setting */
+ acf_dscachefile_setting_ptr /* pointer for setting */
+};
+
+/* Camera Expander ------------------------------------------- */
+
+// TODO: just get this from RNA?
static int acf_dscam_icon(bAnimListElem *UNUSED(ale))
{
return ICON_CAMERA_DATA;
@@ -3388,6 +3471,7 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_DSMAT; /* Material Channel */
animchannelTypeInfo[type++] = &ACF_DSLAM; /* Lamp Channel */
animchannelTypeInfo[type++] = &ACF_DSCAM; /* Camera Channel */
+ animchannelTypeInfo[type++] = &ACF_DSCACHEFILE; /* CacheFile Channel */
animchannelTypeInfo[type++] = &ACF_DSCUR; /* Curve Channel */
animchannelTypeInfo[type++] = &ACF_DSSKEY; /* ShapeKey Channel */
animchannelTypeInfo[type++] = &ACF_DSWOR; /* World Channel */
@@ -4208,6 +4292,8 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
offset += ICON_WIDTH;
}
else if (ale->type == ANIMTYPE_GPLAYER) {
+#if 0
+ /* XXX: Maybe need a better design */
/* color swatch for layer color */
bGPDlayer *gpl = (bGPDlayer *)ale->data;
PointerRNA ptr;
@@ -4216,7 +4302,6 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, &ptr);
UI_block_align_begin(block);
-
UI_block_emboss_set(block, RNA_boolean_get(&ptr, "is_stroke_visible") ? UI_EMBOSS : UI_EMBOSS_NONE);
uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset, yminc, w, ICON_WIDTH,
&ptr, "color", -1,
@@ -4226,11 +4311,11 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset + w, yminc, w, ICON_WIDTH,
&ptr, "fill_color", -1,
0, 0, 0, 0, gpl->info);
-
UI_block_emboss_set(block, UI_EMBOSS_NONE);
UI_block_align_end(block);
-
+
offset += ICON_WIDTH;
+#endif
}
}
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index af9b0a176f5..cb65a9aecad 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -120,6 +120,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
@@ -175,6 +176,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
@@ -275,6 +277,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
@@ -370,6 +373,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
@@ -1686,7 +1690,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 */
- free_gpencil_frames(gpl);
+ BKE_gpencil_free_frames(gpl);
BLI_freelinkN(&gpd->layers, gpl);
break;
}
@@ -2716,6 +2720,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 0d1a13fa95d..a6dc974179d 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -53,6 +53,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_lamp_types.h"
#include "DNA_lattice_types.h"
#include "DNA_linestyle_types.h"
@@ -199,6 +200,16 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
ac->mode = saction->mode;
return true;
+
+ case SACTCONT_CACHEFILE: /* Cache File */ /* XXX review how this mode is handled... */
+ /* update scene-pointer (no need to check for pinning yet, as not implemented) */
+ saction->ads.source = (ID *)ac->scene;
+
+ ac->datatype = ANIMCONT_CHANNEL;
+ ac->data = &saction->ads;
+
+ ac->mode = saction->mode;
+ return true;
case SACTCONT_MASK: /* Mask */ /* XXX review how this mode is handled... */
{
@@ -660,6 +671,19 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
ale->adt = BKE_animdata_from_id(data);
break;
}
+ case ANIMTYPE_DSCACHEFILE:
+ {
+ CacheFile *cache_file = (CacheFile *)data;
+ AnimData *adt = cache_file->adt;
+
+ ale->flag = FILTER_CACHEFILE_OBJD(cache_file);
+
+ ale->key_data = (adt) ? adt->action : NULL;
+ ale->datatype = ALE_ACT;
+
+ ale->adt = BKE_animdata_from_id(data);
+ break;
+ }
case ANIMTYPE_DSCUR:
{
Curve *cu = (Curve *)data;
@@ -1751,6 +1775,42 @@ static size_t animdata_filter_ds_gpencil(bAnimContext *ac, ListBase *anim_data,
return items;
}
+/* Helper for Cache File data integrated with main DopeSheet */
+static size_t animdata_filter_ds_cachefile(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, CacheFile *cache_file, int filter_mode)
+{
+ ListBase tmp_data = {NULL, NULL};
+ size_t tmp_items = 0;
+ size_t items = 0;
+
+ /* add relevant animation channels for Cache File */
+ BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_CACHEFILE_OBJD(cache_file))
+ {
+ /* add animation channels */
+ tmp_items += animfilter_block_data(ac, &tmp_data, ads, &cache_file->id, filter_mode);
+ }
+ END_ANIMFILTER_SUBCHANNELS;
+
+ /* did we find anything? */
+ if (tmp_items) {
+ /* include data-expand widget first */
+ if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+ /* check if filtering by active status */
+ // XXX: active check here needs checking
+ if (ANIMCHANNEL_ACTIVEOK(cache_file)) {
+ ANIMCHANNEL_NEW_CHANNEL(cache_file, ANIMTYPE_DSCACHEFILE, cache_file);
+ }
+ }
+
+ /* now add the list of collected channels */
+ BLI_movelisttolist(anim_data, &tmp_data);
+ BLI_assert(BLI_listbase_is_empty(&tmp_data));
+ items += tmp_items;
+ }
+
+ /* return the number of items added to the list */
+ return items;
+}
+
/* Helper for Mask Editing - mask layers */
static size_t animdata_filter_mask_data(ListBase *anim_data, Mask *mask, const int filter_mode)
{
@@ -2843,6 +2903,12 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b
filter_mode |= ANIMFILTER_SELEDIT;
}
+ /* Cache files level animations (frame duration and such). */
+ CacheFile *cache_file = G.main->cachefiles.first;
+ for (; cache_file; cache_file = cache_file->id.next) {
+ items += animdata_filter_ds_cachefile(ac, anim_data, ads, cache_file, filter_mode);
+ }
+
/* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */
items += animdata_filter_dopesheet_scene(ac, anim_data, ads, scene, filter_mode);
@@ -2954,7 +3020,11 @@ static size_t animdata_filter_animchan(bAnimContext *ac, ListBase *anim_data, bD
case ANIMTYPE_OBJECT:
items += animdata_filter_dopesheet_ob(ac, anim_data, ads, channel->data, filter_mode);
break;
-
+
+ case ANIMTYPE_DSCACHEFILE:
+ items += animdata_filter_ds_cachefile(ac, anim_data, ads, channel->data, filter_mode);
+ break;
+
case ANIMTYPE_ANIMDATA:
items += animfilter_block_data(ac, anim_data, ads, channel->id, filter_mode);
break;
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 6e776953356..5f675e690b9 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -44,6 +44,7 @@
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_gpencil_types.h"
@@ -965,6 +966,37 @@ void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, DLRBT_Tree *bl
ANIM_animdata_freelist(&anim_data);
}
+void cachefile_to_keylist(bDopeSheet *ads, CacheFile *cache_file, DLRBT_Tree *keys, DLRBT_Tree *blocks)
+{
+ if (cache_file == NULL) {
+ return;
+ }
+
+ /* create a dummy wrapper data to work with */
+ bAnimListElem dummychan = {NULL};
+ dummychan.type = ANIMTYPE_DSCACHEFILE;
+ dummychan.data = cache_file;
+ dummychan.id = &cache_file->id;
+ dummychan.adt = cache_file->adt;
+
+ bAnimContext ac = {NULL};
+ ac.ads = ads;
+ ac.data = &dummychan;
+ ac.datatype = ANIMCONT_CHANNEL;
+
+ /* get F-Curves to take keyframes from */
+ ListBase anim_data = { NULL, NULL };
+ int filter = ANIMFILTER_DATA_VISIBLE; // curves only
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* loop through each F-Curve, grabbing the keyframes */
+ for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ fcurve_to_keylist(ale->adt, ale->data, keys, blocks);
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+}
+
void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, DLRBT_Tree *blocks)
{
BezTriple *bezt;
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 0c0f54f0179..98be77b491f 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -930,11 +930,18 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
/* update F-Curve flags to ensure proper behaviour for property type */
update_autoflags_fcurve_direct(fcu, prop);
-
+
/* adjust frame on which to add keyframe */
if ((flag & INSERTKEY_DRIVER) && (fcu->driver)) {
- /* for making it easier to add corrective drivers... */
- cfra = evaluate_driver(fcu->driver, cfra);
+ PathResolvedRNA anim_rna;
+
+ if (RNA_path_resolved_create(&ptr, prop, fcu->array_index, &anim_rna)) {
+ /* for making it easier to add corrective drivers... */
+ cfra = evaluate_driver(&anim_rna, fcu->driver, cfra);
+ }
+ else {
+ cfra = 0.0f;
+ }
}
/* obtain value to give keyframe */
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 4d0a2fa53cd..2d8fc76ee7e 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -64,8 +64,8 @@
#endif
/* Distance between input samples */
-#define STROKE_SAMPLE_DIST_MIN_PX 3
-#define STROKE_SAMPLE_DIST_MAX_PX 6
+#define STROKE_SAMPLE_DIST_MIN_PX 1
+#define STROKE_SAMPLE_DIST_MAX_PX 3
/* Distance between start/end points to consider cyclic */
#define STROKE_CYCLIC_DIST_PX 8
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 79a2c494239..4ef76f5ee25 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2008, Blender Foundation
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -52,6 +52,7 @@
#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"
@@ -94,9 +95,32 @@ typedef enum eDrawStrokeFlags {
#define GP_DRAWTHICKNESS_SPECIAL 3
/* ----- Tool Buffer Drawing ------ */
+/* helper function to set color of buffer point */
+static void gp_set_tpoint_color(tGPspoint *pt, float ink[4])
+{
+ float alpha = ink[3] * pt->strength;
+ CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
+ glColor4f(ink[0], ink[1], ink[2], alpha);
+}
+
+/* helper function to set color of point */
+static void gp_set_point_color(bGPDspoint *pt, float ink[4])
+{
+ float alpha = ink[3] * pt->strength;
+ CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
+ glColor4f(ink[0], ink[1], ink[2], alpha);
+}
+
+/* helper function to set color and point */
+static void gp_set_color_and_tpoint(tGPspoint *pt, float ink[4])
+{
+ gp_set_tpoint_color(pt, ink);
+ glVertex2iv(&pt->x);
+}
/* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
-static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickness, short dflag, short sflag)
+static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickness,
+ short dflag, short sflag, float ink[4])
{
tGPspoint *pt;
int i;
@@ -113,7 +137,8 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
/* if drawing a single point, draw it larger */
glPointSize((float)(thickness + 2) * points->pressure);
glBegin(GL_POINTS);
- glVertex2iv(&points->x);
+
+ gp_set_color_and_tpoint(points, ink);
glEnd();
}
else if (sflag & GP_STROKE_ERASER) {
@@ -138,15 +163,18 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
glBegin(GL_LINE_STRIP);
/* need to roll-back one point to ensure that there are no gaps in the stroke */
- if (i != 0) glVertex2iv(&(pt - 1)->x);
+ if (i != 0) {
+ gp_set_color_and_tpoint((pt - 1), ink);
+ }
/* now the point we want... */
- glVertex2iv(&pt->x);
+ gp_set_color_and_tpoint(pt, ink);
oldpressure = pt->pressure;
}
- else
- glVertex2iv(&pt->x);
+ else {
+ gp_set_color_and_tpoint(pt, ink);
+ }
}
glEnd();
@@ -155,37 +183,35 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
}
/* --------- 2D Stroke Drawing Helpers --------- */
-
-/* helper function to calculate x-y drawing coordinates for 2D points */
-static void gp_calc_2d_stroke_xy(bGPDspoint *pt, short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
+/* change in parameter list */
+static void gp_calc_2d_stroke_fxy(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->x;
- r_co[1] = pt->y;
+ r_co[0] = pt[0];
+ r_co[1] = pt[1];
}
else if (sflag & GP_STROKE_2DIMAGE) {
- const float x = (float)((pt->x * winx) + offsx);
- const float y = (float)((pt->y * winy) + offsy);
-
+ 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->x / 100 * winx) + offsx;
- const float y = (float)(pt->y / 100 * winy) + offsy;
-
+ 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;
}
}
-
/* ----------- Volumetric Strokes --------------- */
/* draw a 2D buffer stroke in "volumetric" style
* NOTE: the stroke buffer doesn't have any coordinate offsets/transforms
*/
static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, short thickness,
- short dflag, short UNUSED(sflag))
+ short dflag, short UNUSED(sflag), float ink[4])
{
GLUquadricObj *qobj = gluNewQuadric();
float modelview[4][4];
@@ -216,6 +242,7 @@ static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, s
glLoadMatrixf((float *)modelview);
/* draw the disk using the current state... */
+ gp_set_tpoint_color(pt, ink);
gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1);
@@ -229,7 +256,8 @@ static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, s
/* draw a 2D strokes in "volumetric" style */
static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, short thickness,
short dflag, short sflag,
- int offsx, int offsy, int winx, int winy)
+ int offsx, int offsy, int winx, int winy,
+ float diff_mat[4][4], float ink[4])
{
GLUquadricObj *qobj = gluNewQuadric();
float modelview[4][4];
@@ -238,7 +266,7 @@ static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, shor
bGPDspoint *pt;
int i;
-
+ float fpt[3];
/* HACK: We need a scale factor for the drawing in the image editor,
* which seems to use 1 unit as it's maximum size, whereas everything
@@ -256,10 +284,14 @@ static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, shor
glPushMatrix();
for (i = 0, pt = points; i < totpoints; i++, pt++) {
+ /* color of point */
+ gp_set_point_color(pt, ink);
+
/* set the transformed position */
float co[2];
- gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
translate_m4(modelview, co[0], co[1], 0.0f);
glLoadMatrixf((float *)modelview);
@@ -276,8 +308,9 @@ static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, shor
}
/* draw a 3D stroke in "volumetric" style */
-static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, short thickness,
- short UNUSED(dflag), short UNUSED(sflag))
+static void gp_draw_stroke_volumetric_3d(
+ bGPDspoint *points, int totpoints, short thickness,
+ short UNUSED(dflag), short UNUSED(sflag), float diff_mat[4][4], float ink[4])
{
GLUquadricObj *qobj = gluNewQuadric();
@@ -286,7 +319,7 @@ static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, shor
bGPDspoint *pt;
int i;
-
+ float fpt[3];
/* Get the basic modelview matrix we use for performing calculations */
glGetFloatv(GL_MODELVIEW_MATRIX, (float *)base_modelview);
@@ -305,8 +338,13 @@ static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, shor
glPushMatrix();
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
+ /* color of point */
+ gp_set_point_color(pt, ink);
+
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+
/* apply translation to base_modelview, so that the translated point is put in the right place */
- translate_m4(base_modelview, pt->x, pt->y, pt->z);
+ translate_m4(base_modelview, fpt[0], fpt[1], fpt[2]);
/* copy the translation component to the billboard matrix we're going to use,
* then reset the base matrix to the original values so that we can do the same
@@ -378,9 +416,9 @@ static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d
static void gp_triangulate_stroke_fill(bGPDstroke *gps)
{
BLI_assert(gps->totpoints >= 3);
- gps->tot_triangles = gps->totpoints - 2;
-
+
/* 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");
float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
@@ -390,6 +428,8 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
gp_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)gps->totpoints, direction, (unsigned int(*)[3])tmp_triangles);
+ /* Number of triangles */
+ gps->tot_triangles = gps->totpoints - 2;
/* save triangulation data in stroke cache */
if (gps->tot_triangles > 0) {
if (gps->triangles == NULL) {
@@ -399,9 +439,7 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
}
- int i;
-
- for (i = 0; i < gps->tot_triangles; i++) {
+ for (int i = 0; i < gps->tot_triangles; i++) {
bGPDtriangle *stroke_triangle = &gps->triangles[i];
stroke_triangle->v1 = tmp_triangles[i][0];
stroke_triangle->v2 = tmp_triangles[i][1];
@@ -428,21 +466,27 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
/* draw fills for shapes */
-static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short dflag, int offsx, int offsy, int winx, int winy)
+static void gp_draw_stroke_fill(
+ bGPdata *gpd, bGPDstroke *gps,
+ int offsx, int offsy, int winx, int winy, float diff_mat[4][4])
{
+ bGPDpalettecolor *palcolor;
+ int i;
+ float fpt[3];
+
BLI_assert(gps->totpoints >= 3);
-
+
+ palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+
/* Triangulation fill if high quality flag is enabled */
- if (dflag & GP_DRAWDATA_HQ_FILL) {
+ if (palcolor->flag & PC_COLOR_HQ_FILL) {
bGPDtriangle *stroke_triangle;
bGPDspoint *pt;
- int i;
-
+
/* 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);
}
-
/* Draw all triangles for filling the polygon (cache must be calculated before) */
BLI_assert(gps->tot_triangles >= 1);
glBegin(GL_TRIANGLES);
@@ -450,32 +494,33 @@ static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short
if (gps->flag & GP_STROKE_3DSPACE) {
/* vertex 1 */
pt = &gps->points[stroke_triangle->v1];
- glVertex3fv(&pt->x);
-
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
/* vertex 2 */
pt = &gps->points[stroke_triangle->v2];
- glVertex3fv(&pt->x);
-
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
/* vertex 3 */
pt = &gps->points[stroke_triangle->v3];
- glVertex3fv(&pt->x);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
}
else {
float co[2];
-
/* vertex 1 */
pt = &gps->points[stroke_triangle->v1];
- gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
-
/* vertex 2 */
pt = &gps->points[stroke_triangle->v2];
- gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
-
/* vertex 3 */
pt = &gps->points[stroke_triangle->v3];
- gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
}
}
@@ -483,30 +528,31 @@ static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short
}
else {
/* As an initial implementation, we use the OpenGL filled polygon drawing
- * here since it's the easiest option to implement for this case. It does
- * come with limitations (notably for concave shapes), though it works well
- * enough for many simple situations.
- *
- * We keep this legacy implementation around despite now having the high quality
- * fills, as this is necessary for keeping everything working nicely for files
- * created using old versions of Blender which may have depended on the artifacts
- * the old fills created.
- */
+ * here since it's the easiest option to implement for this case. It does
+ * come with limitations (notably for concave shapes), though it shouldn't
+ * be much of an issue in most cases.
+ *
+ * We keep this legacy implementation around despite now having the high quality
+ * fills, as this is necessary for keeping everything working nicely for files
+ * created using old versions of Blender which may have depended on the artifacts
+ * the old fills created.
+ */
bGPDspoint *pt;
- int i;
-
+
glBegin(GL_POLYGON);
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (gps->flag & GP_STROKE_3DSPACE) {
- glVertex3fv(&pt->x);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
}
else {
float co[2];
-
- gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
}
}
+
glEnd();
}
}
@@ -514,23 +560,33 @@ static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short
/* ----- Existing Strokes Drawing (3D and Point) ------ */
/* draw a given stroke - just a single dot (only one point) */
-static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dflag, short sflag,
- int offsx, int offsy, int winx, int winy)
+static void gp_draw_stroke_point(
+ bGPDspoint *points, short thickness, short dflag, short sflag,
+ int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4])
{
+ float fpt[3];
+ bGPDspoint *pt = &points[0];
+
+ /* color of point */
+ gp_set_point_color(pt, ink);
+
/* set point thickness (since there's only one of these) */
glPointSize((float)(thickness + 2) * points->pressure);
+ /* get final position using parent matrix */
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+
/* draw point */
if (sflag & GP_STROKE_3DSPACE) {
glBegin(GL_POINTS);
- glVertex3fv(&points->x);
+ glVertex3fv(fpt);
glEnd();
}
else {
float co[2];
/* get coordinates of point */
- gp_calc_2d_stroke_xy(points, sflag, offsx, offsy, winx, winy, co);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
/* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok
* - also mandatory in if Image Editor 'image-based' dot
@@ -559,16 +615,21 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla
}
/* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
-static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug, short UNUSED(sflag))
+static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug,
+ short UNUSED(sflag), float diff_mat[4][4], float ink[4], bool cyclic)
{
- bGPDspoint *pt;
+ bGPDspoint *pt, *pt2;
float curpressure = points[0].pressure;
int i;
-
+ float fpt[3];
+ float cyclic_fpt[3];
+
/* draw stroke curve */
glLineWidth(max_ff(curpressure * thickness, 1.0f));
glBegin(GL_LINE_STRIP);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
+ gp_set_point_color(pt, ink);
+
/* 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.
@@ -580,15 +641,29 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
glBegin(GL_LINE_STRIP);
/* need to roll-back one point to ensure that there are no gaps in the stroke */
- if (i != 0) glVertex3fv(&(pt - 1)->x);
+ if (i != 0) {
+ pt2 = pt - 1;
+ mul_v3_m4v3(fpt, diff_mat, &pt2->x);
+ glVertex3fv(fpt);
+ }
/* now the point we want... */
- glVertex3fv(&pt->x);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
}
else {
- glVertex3fv(&pt->x);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
+ }
+ /* saves first point to use in cyclic */
+ if (i == 0) {
+ copy_v3_v3(cyclic_fpt, fpt);
}
}
+ /* if cyclic draw line to first point */
+ if (cyclic) {
+ glVertex3fv(cyclic_fpt);
+ }
glEnd();
/* draw debug points of curve on top? */
@@ -597,9 +672,12 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
glPointSize((float)(thickness + 2));
glBegin(GL_POINTS);
- for (i = 0, pt = points; i < totpoints && pt; i++, pt++)
- glVertex3fv(&pt->x);
+ for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
+ }
glEnd();
+
}
}
@@ -607,7 +685,7 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
/* draw a given stroke in 2d */
static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
- bool debug, int offsx, int offsy, int winx, int winy)
+ bool debug, int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4])
{
/* otherwise thickness is twice that of the 3D view */
float thickness = (float)thickness_s * 0.5f;
@@ -625,6 +703,7 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
bGPDspoint *pt1, *pt2;
float pm[2];
int i;
+ float fpt[3];
glShadeModel(GL_FLAT);
glBegin(GL_QUADS);
@@ -635,10 +714,13 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
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 points */
- gp_calc_2d_stroke_xy(pt1, sflag, offsx, offsy, winx, winy, s0);
- gp_calc_2d_stroke_xy(pt2, sflag, offsx, offsy, winx, winy, s1);
+ mul_v3_m4v3(fpt, diff_mat, &pt1->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
+
+ mul_v3_m4v3(fpt, diff_mat, &pt2->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1);
/* calculate gradient and normal - 'angle'=(ny/nx) */
m1[1] = s1[1] - s0[1];
@@ -650,6 +732,9 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
/* always use pressure from first point here */
pthick = (pt1->pressure * thickness * scalefac);
+ /* color of point */
+ gp_set_point_color(pt1, ink);
+
/* if the first segment, start of segment is segment's normal */
if (i == 0) {
/* draw start cap first
@@ -725,6 +810,9 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
/* for once, we use second point's pressure (otherwise it won't be drawn) */
pthick = (pt2->pressure * thickness * scalefac);
+ /* color of point */
+ gp_set_point_color(pt2, ink);
+
/* calculate points for end of segment */
mt[0] = m2[0] * pthick;
mt[1] = m2[1] * pthick;
@@ -770,14 +858,15 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
if (debug) {
bGPDspoint *pt;
int i;
-
+ float fpt[3];
+
glPointSize((float)(thickness_s + 2));
glBegin(GL_POINTS);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
float co[2];
-
- gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
}
glEnd();
@@ -818,26 +907,45 @@ static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
}
/* draw a set of strokes */
-static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
- bool debug, short lthick, const float color[4], const float fill_color[4])
+static void gp_draw_strokes(
+ bGPdata *gpd, 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, float diff_mat[4][4])
{
bGPDstroke *gps;
-
+ float tcolor[4];
+ float tfill[4];
+ short sthickness;
+ float ink[4];
+
for (gps = 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, 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) ||
+ /* if onion and ghost flag do not draw*/
+ (onion && (palcolor->flag & PC_COLOR_ONIONSKIN)))
+ {
+ continue;
+ }
+
+ /* calculate thickness */
+ sthickness = gps->thickness + lthick;
+
/* 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);
glEnable(GL_DEPTH_TEST);
-
+
/* first arg is normally rv3d->dist, but this isn't
* available here and seems to work quite well without */
bglPolygonOffset(1.0f, 1.0f);
@@ -846,34 +954,65 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
glPolygonOffset(-1.0f, -1.0f);
#endif
}
-
+
/* 3D Fill */
- if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
- glColor4fv(fill_color);
- gp_draw_stroke_fill(gps, lthick, dflag, offsx, offsy, winx, winy);
+ //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 (!onion) {
+ glColor4fv(tfill);
+ }
+ else {
+ if (custonion) {
+ glColor4fv(tintcolor);
+ }
+ else {
+ ARRAY_SET_ITEMS(tfill, UNPACK3(palcolor->fill), tintcolor[3]);
+ glColor4fv(tfill);
+ }
+ }
+ gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
+ }
}
-
+
/* 3D Stroke */
- glColor4fv(color);
-
- if (dflag & GP_DRAWDATA_VOLUMETRIC) {
+ /* 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;
+ copy_v4_v4(ink, tcolor);
+ }
+ else {
+ if (custonion) {
+ copy_v4_v4(ink, tintcolor);
+ }
+ else {
+ ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
+ copy_v4_v4(ink, tcolor);
+ }
+ }
+ if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
/* volumetric stroke drawing */
- gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, lthick, dflag, gps->flag);
+ gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, diff_mat, ink);
}
else {
/* 3D Lines - OpenGL primitives-based */
if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
+ diff_mat, ink);
}
else {
- gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug, gps->flag);
+ gp_draw_stroke_3d(gps->points, gps->totpoints, sthickness, debug, gps->flag,
+ diff_mat, ink, gps->flag & GP_STROKE_CYCLIC);
}
}
-
if (no_xray) {
glDepthMask(mask_orig);
glDisable(GL_DEPTH_TEST);
-
+
bglPolygonOffset(0.0, 0.0);
#if 0
glDisable(GL_POLYGON_OFFSET_LINE);
@@ -883,25 +1022,58 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
}
else {
/* 2D - Fill */
- if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
- glColor4fv(fill_color);
- gp_draw_stroke_fill(gps, lthick, dflag, offsx, offsy, winx, winy);
+ 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 (!onion) {
+ glColor4fv(tfill);
+ }
+ else {
+ if (custonion) {
+ glColor4fv(tintcolor);
+ }
+ else {
+ ARRAY_SET_ITEMS(tfill, palcolor->fill[0], palcolor->fill[1], palcolor->fill[2],
+ tintcolor[3]);
+ glColor4fv(tfill);
+ }
+ }
+ gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
+ }
}
-
+
/* 2D Strokes... */
- glColor4fv(color);
-
- if (dflag & GP_DRAWDATA_VOLUMETRIC) {
+ /* 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;
+ copy_v4_v4(ink, tcolor);
+ }
+ else {
+ if (custonion) {
+ copy_v4_v4(ink, tintcolor);
+ }
+ else {
+ ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
+ copy_v4_v4(ink, tcolor);
+ }
+ }
+ if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
/* blob/disk-based "volumetric" drawing */
- gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag,
+ offsx, offsy, winx, winy, diff_mat, ink);
}
else {
/* normal 2D strokes */
if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
+ diff_mat, ink);
}
else {
- gp_draw_stroke_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy);
+ gp_draw_stroke_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, debug,
+ offsx, offsy, winx, winy, diff_mat, ink);
}
}
}
@@ -909,13 +1081,19 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
}
/* Draw selected verts for strokes being edited */
-static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag, const float tcolor[3])
+static void gp_draw_strokes_edit(
+ bGPdata *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag,
+ short lflag, float diff_mat[4][4], float alpha)
{
bGPDstroke *gps;
+ /* 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) {
@@ -939,7 +1117,8 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
bGPDspoint *pt;
float vsize, bsize;
int i;
-
+ float fpt[3];
+
/* check if stroke can be drawn */
if (gp_can_draw_stroke(gps, dflag) == false)
continue;
@@ -951,6 +1130,19 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
if ((gps->flag & GP_STROKE_SELECT) == 0)
continue;
+ /* verify palette color lock */
+ {
+ bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+ if (palcolor != NULL) {
+ if (palcolor->flag & PC_COLOR_HIDE) {
+ continue;
+ }
+ if (((lflag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED)) {
+ continue;
+ }
+ }
+ }
+
/* Get size of verts:
* - The selected state needs to be larger than the unselected state so that
* they stand out more.
@@ -966,25 +1158,23 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
}
/* First Pass: Draw all the verts (i.e. these become the unselected state) */
- if (tcolor != NULL) {
- /* for now, we assume that the base color of the points is not too close to the real color */
- glColor3fv(tcolor);
- }
- else {
- /* this doesn't work well with the default theme and black strokes... */
- UI_ThemeColor(TH_GP_VERTEX);
- }
+ /* 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);
+ glColor3fv(palcolor->color);
+
glPointSize(bsize);
glBegin(GL_POINTS);
for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
if (gps->flag & GP_STROKE_3DSPACE) {
- glVertex3fv(&pt->x);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
}
else {
float co[2];
-
- gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
}
}
@@ -992,24 +1182,54 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
/* Second Pass: Draw only verts which are selected */
- UI_ThemeColor(TH_GP_VERTEX_SELECT);
+ float curColor[4];
+ UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, curColor);
+ glColor4f(curColor[0], curColor[1], curColor[2], alpha);
+
glPointSize(vsize);
glBegin(GL_POINTS);
for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
if (gps->flag & GP_STROKE_3DSPACE) {
- glVertex3fv(&pt->x);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
}
else {
float co[2];
- gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
}
}
}
glEnd();
+
+ /* Draw start and end point if enabled stroke direction hint */
+ if ((gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1)) {
+ bGPDspoint *p;
+
+ glPointSize(vsize + 4);
+ glBegin(GL_POINTS);
+
+ /* start point in green bigger */
+ glColor3f(0.0f, 1.0f, 0.0f);
+ p = &gps->points[0];
+ mul_v3_m4v3(fpt, diff_mat, &p->x);
+ glVertex3fv(fpt);
+ glEnd();
+
+ /* end point in red smaller */
+ glPointSize(vsize + 1);
+ glBegin(GL_POINTS);
+
+ glColor3f(1.0f, 0.0f, 0.0f);
+ p = &gps->points[gps->totpoints - 1];
+ mul_v3_m4v3(fpt, diff_mat, &p->x);
+ glVertex3fv(fpt);
+ glEnd();
+ }
}
@@ -1031,18 +1251,20 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
/* ----- General Drawing ------ */
/* draw onion-skinning for a layer */
-static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
- int UNUSED(cfra), int dflag, bool debug, short lthick)
+static void gp_draw_onionskins(
+ bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
+ int UNUSED(cfra), int dflag, bool debug, float diff_mat[4][4])
{
- const float alpha = gpl->color[3];
+ const float default_color[3] = {UNPACK3(U.gpencil_new_layer_col)};
+ const float alpha = 1.0f;
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, gpl->color);
+ copy_v3_v3(color, default_color);
}
if (gpl->gstep > 0) {
@@ -1056,7 +1278,8 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
/* alpha decreases with distance from curframe index */
fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
color[3] = alpha * fac * 0.66f;
- gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+ 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;
@@ -1066,7 +1289,8 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
/* 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(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+ 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 {
@@ -1079,7 +1303,7 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
copy_v3_v3(color, gpl->gcolor_next);
}
else {
- copy_v3_v3(color, gpl->color);
+ copy_v3_v3(color, default_color);
}
if (gpl->gstep_next > 0) {
@@ -1093,7 +1317,8 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
/* alpha decreases with distance from curframe index */
fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
color[3] = alpha * fac * 0.66f;
- gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+ 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;
@@ -1103,34 +1328,38 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
/* 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(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+ 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);
}
}
else {
/* don't draw - disabled */
}
- /* 3) restore alpha */
- glColor4fv(gpl->color);
}
/* 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)
+static void gp_draw_data_layers(
+ bGPDbrush *brush, float alpha, bGPdata *gpd,
+ int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
bGPDlayer *gpl;
-
+ float diff_mat[4][4];
+
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
bGPDframe *gpf;
-
+ /* calculate parent position */
+ ED_gpencil_parent_location(gpl, diff_mat);
+
bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false;
- short lthick = gpl->thickness;
+ short lthick = brush->thickness + gpl->thickness;
/* don't draw layer if hidden */
if (gpl->flag & GP_LAYER_HIDE)
continue;
/* get frame to draw */
- gpf = gpencil_layer_getframe(gpl, cfra, 0);
+ gpf = BKE_gpencil_layer_getframe(gpl, cfra, 0);
if (gpf == NULL)
continue;
@@ -1155,9 +1384,6 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
/* HQ fills... */
GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_HQ_FILL), GP_DRAWDATA_HQ_FILL);
- /* fill strokes... */
- // XXX: this is not a very good limit
- GP_DRAWFLAG_APPLY((gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH), GP_DRAWDATA_FILL);
#undef GP_DRAWFLAG_APPLY
/* draw 'onionskins' (frame left + right) */
@@ -1165,11 +1391,12 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
/* Drawing method - only immediately surrounding (gstep = 0),
* or within a frame range on either side (gstep > 0)
*/
- gp_draw_onionskins(gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, lthick);
+ gp_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, diff_mat);
}
/* draw the strokes already in active frame */
- gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, gpl->color, gpl->fill);
+ gp_draw_strokes(gpd, gpf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness,
+ gpl->opacity, gpl->tintcolor, false, false, diff_mat);
/* Draw verts of selected strokes
* - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
@@ -1183,8 +1410,7 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
(gpl->flag & GP_LAYER_LOCKED) == 0 &&
(gpd->flag & GP_DATA_STROKE_EDITMODE))
{
- gp_draw_strokes_edit(gpf, offsx, offsy, winx, winy, dflag,
- (gpl->color[3] < 0.95f) ? gpl->color : NULL);
+ gp_draw_strokes_edit(gpd, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, diff_mat, alpha);
}
/* Check if may need to draw the active stroke cache, only if this layer is the active layer
@@ -1194,7 +1420,7 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
(gpf->flag & GP_FRAME_PAINT))
{
/* Set color for drawing buffer stroke - since this may not be set yet */
- glColor4fv(gpl->color);
+ // glColor4fv(gpl->color);
/* Buffer stroke needs to be drawn with a different linestyle
* to help differentiate them from normal strokes.
@@ -1202,11 +1428,12 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
* It should also be noted that sbuffer contains temporary point types
* i.e. tGPspoints NOT bGPDspoints
*/
- if (gpl->flag & GP_LAYER_VOLUMETRIC) {
- gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
+ if (gpd->sflag & PC_COLOR_VOLUMETRIC) {
+ gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick,
+ dflag, gpd->sbuffer_sflag, gpd->scolor);
}
else {
- gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
+ gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor);
}
}
}
@@ -1258,7 +1485,9 @@ static void gp_draw_status_text(bGPdata *gpd, ARegion *ar)
}
/* draw grease-pencil datablock */
-static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
+static void gp_draw_data(
+ bGPDbrush *brush, float alpha, bGPdata *gpd,
+ int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
/* reset line drawing style (in case previous user didn't reset) */
setlinestyle(0);
@@ -1276,7 +1505,7 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy,
glEnable(GL_BLEND);
/* draw! */
- gp_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag);
+ gp_draw_data_layers(brush, alpha, gpd, offsx, offsy, winx, winy, cfra, dflag);
/* turn off alpha blending, then smooth lines */
glDisable(GL_BLEND); // alpha blending
@@ -1303,14 +1532,25 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i
}
if (gpd_source) {
- gp_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag);
+ ToolSettings *ts = scene->toolsettings;
+ bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
+ if (brush != NULL) {
+ gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source,
+ offsx, offsy, winx, winy, cfra, dflag);
+ }
+
}
}
/* 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);
+ ToolSettings *ts = scene->toolsettings;
+ bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
+ if (brush != NULL) {
+ gp_draw_data(brush, ts->gp_sculpt.alpha, gpd,
+ offsx, offsy, winx, winy, cfra, dflag);
+ }
}
}
@@ -1479,6 +1719,7 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, AReg
/* draw it! */
gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
+
}
void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index 738496a67c6..bd4856f1b93 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -253,7 +253,7 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl)
gpfn = gpf->next;
if (gpf->flag & GP_FRAME_SELECT)
- changed |= gpencil_layer_delframe(gpl, gpf);
+ changed |= BKE_gpencil_layer_delframe(gpl, gpf);
}
return changed;
@@ -277,7 +277,7 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl)
bGPDframe *gpfd;
/* duplicate frame, and deselect self */
- gpfd = gpencil_frame_duplicate(gpf);
+ gpfd = BKE_gpencil_frame_duplicate(gpf);
gpf->flag &= ~GP_FRAME_SELECT;
BLI_insertlinkafter(&gpl->frames, gpf, gpfd);
@@ -323,7 +323,7 @@ static int gp_anim_copy_cfra = 0;
/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ED_gpencil_anim_copybuf_free(void)
{
- free_gpencil_layers(&gp_anim_copybuf);
+ BKE_gpencil_free_layers(&gp_anim_copybuf);
BLI_listbase_clear(&gp_anim_copybuf);
gp_anim_copy_firstframe = 999999999;
@@ -364,7 +364,7 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
/* if frame is selected, make duplicate it and its strokes */
if (gpf->flag & GP_FRAME_SELECT) {
/* make a copy of this frame */
- bGPDframe *new_frame = gpencil_frame_duplicate(gpf);
+ bGPDframe *new_frame = BKE_gpencil_frame_duplicate(gpf);
BLI_addtail(&copied_frames, new_frame);
/* extend extents for keyframes encountered */
@@ -475,7 +475,7 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
gpfs->framenum += offset;
/* get frame to copy data into (if no frame returned, then just ignore) */
- gpf = gpencil_layer_getframe(gpld, gpfs->framenum, 1);
+ gpf = BKE_gpencil_layer_getframe(gpld, gpfs->framenum, 1);
if (gpf) {
bGPDstroke *gps, *gpsn;
@@ -498,7 +498,7 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* if no strokes (i.e. new frame) added, free gpf */
if (BLI_listbase_is_empty(&gpf->strokes))
- gpencil_layer_delframe(gpld, gpf);
+ BKE_gpencil_layer_delframe(gpld, gpf);
}
/* unapply offset from buffer-frame */
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index 0271afd6827..fcb2ce02bde 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2015, Blender Foundation
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -51,6 +51,7 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -223,9 +224,26 @@ static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i
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)
+ {
+ gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
+ }
+
/* perform smoothing */
- return gp_smooth_stroke(gps, i, inf, affect_pressure);
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_POSITION) {
+ gp_smooth_stroke(gps, i, inf, affect_pressure);
+ }
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_STRENGTH) {
+ gp_smooth_stroke_strength(gps, i, inf);
+ }
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_THICKNESS) {
+ gp_smooth_stroke_thickness(gps, i, inf);
+ }
+
+ return true;
}
/* ----------------------------------------------- */
@@ -268,6 +286,41 @@ static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
/* ----------------------------------------------- */
+/* Color Strength Brush */
+
+/* Make color more or less transparent by the specified amounts */
+static bool gp_brush_strength_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int i,
+ const int radius, const int co[2])
+{
+ bGPDspoint *pt = gps->points + i;
+ 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;
+
+ /* 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 */
+ pt->strength -= inf;
+ }
+ else {
+ /* make line thicker - increase stroke pressure */
+ pt->strength += inf;
+ }
+
+ /* Strength should stay within [0.0, 1.0] */
+ CLAMP(pt->strength, 0.0f, 1.0f);
+
+ return true;
+}
+
+
+/* ----------------------------------------------- */
/* Grab Brush */
/* Custom data per stroke for the Grab Brush
@@ -373,11 +426,12 @@ 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)
+static void gp_brush_grab_apply_cached(
+ tGP_BrushEditData *gso, bGPDstroke *gps, bool parented, float diff_mat[4][4])
{
tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
int i;
-
+
/* Apply dvec to all of the stored points */
for (i = 0; i < data->size; i++) {
bGPDspoint *pt = &gps->points[data->points[i]];
@@ -385,9 +439,23 @@ static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso, bGPDstroke *gps)
/* 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);
+ }
- /* apply */
- add_v3_v3(&pt->x, delta);
}
}
@@ -592,62 +660,92 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
*/
const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f;
const float fac = BLI_frand() * inf;
-
- /* Jitter is applied perpendicular to the mouse movement vector
- * - We compute all effects in screenspace (since it's easier)
- * and then project these to get the points/distances in
- * viewspace as needed
- */
- float mvec[2], svec[2];
-
- /* mouse movement in ints -> floats */
- mvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
- mvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
-
- /* rotate mvec by 90 degrees... */
- svec[0] = -mvec[1];
- svec[1] = mvec[0];
-
- //printf("svec = %f %f, ", svec[0], svec[1]);
-
- /* scale the displacement by the random displacement, and apply */
- if (BLI_frand() > 0.5f) {
- mul_v2_fl(svec, -fac);
- }
- else {
- mul_v2_fl(svec, fac);
+ /* 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)
+ {
+ gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
}
-
- //printf("%f %f (%f), nco = {%f %f}, co = %d %d\n", svec[0], svec[1], fac, nco[0], nco[1], co[0], co[1]);
-
- /* convert to dataspace */
- if (gps->flag & GP_STROKE_3DSPACE) {
- /* 3D: Project to 3D space */
- if (gso->sa->spacetype == SPACE_VIEW3D) {
- bool flip;
- RegionView3D *rv3d = gso->ar->regiondata;
- float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip);
- if (flip == false) {
- float dvec[3];
- ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac);
- add_v3_v3(&pt->x, dvec);
+
+ /* apply random to position */
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_POSITION) {
+ /* Jitter is applied perpendicular to the mouse movement vector
+ * - We compute all effects in screenspace (since it's easier)
+ * and then project these to get the points/distances in
+ * viewspace as needed
+ */
+ float mvec[2], svec[2];
+
+ /* mouse movement in ints -> floats */
+ mvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ mvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+
+ /* rotate mvec by 90 degrees... */
+ svec[0] = -mvec[1];
+ svec[1] = mvec[0];
+
+ /* scale the displacement by the random displacement, and apply */
+ if (BLI_frand() > 0.5f) {
+ mul_v2_fl(svec, -fac);
+ }
+ else {
+ mul_v2_fl(svec, fac);
+ }
+
+ //printf("%f %f (%f), nco = {%f %f}, co = %d %d\n", svec[0], svec[1], fac, nco[0], nco[1], co[0], co[1]);
+
+ /* convert to dataspace */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* 3D: Project to 3D space */
+ if (gso->sa->spacetype == SPACE_VIEW3D) {
+ bool flip;
+ RegionView3D *rv3d = gso->ar->regiondata;
+ float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip);
+ if (flip == false) {
+ float dvec[3];
+ ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac);
+ add_v3_v3(&pt->x, dvec);
+ }
+ }
+ else {
+ /* ERROR */
+ BLI_assert("3D stroke being sculpted in non-3D view");
}
}
else {
- /* ERROR */
- BLI_assert("3D stroke being sculpted in non-3D view");
+ /* 2D: As-is */
+ // XXX: v2d scaling/offset?
+ float nco[2];
+ nco[0] = (float)co[0] + svec[0];
+ nco[1] = (float)co[1] + svec[1];
+
+ copy_v2_v2(&pt->x, nco);
}
}
- else {
- /* 2D: As-is */
- // XXX: v2d scaling/offset?
- float nco[2];
- nco[0] = (float)co[0] + svec[0];
- nco[1] = (float)co[1] + svec[1];
-
- copy_v2_v2(&pt->x, nco);
+ /* apply random to strength */
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_STRENGTH) {
+ if (BLI_frand() > 0.5f) {
+ pt->strength += fac;
+ }
+ else {
+ pt->strength -= fac;
+ }
+ CLAMP_MIN(pt->strength, 0.0f);
+ CLAMP_MAX(pt->strength, 1.0f);
}
-
+ /* apply random to thickness (use pressure) */
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_THICKNESS) {
+ if (BLI_frand() > 0.5f) {
+ pt->pressure += fac;
+ }
+ else {
+ pt->pressure -= fac;
+ }
+ /* only limit lower value */
+ CLAMP_MIN(pt->pressure, 0.0f);
+ }
+
/* done */
return true;
}
@@ -743,7 +841,7 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
Scene *scene = gso->scene;
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, true);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
bGPDstroke *gps;
float delta[3];
@@ -1087,7 +1185,7 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
*/
// XXX: should this be allowed when framelock is enabled?
if (gpf->framenum != cfra) {
- gpencil_frame_addcopy(gpl, cfra);
+ BKE_gpencil_frame_addcopy(gpl, cfra);
}
}
}
@@ -1099,7 +1197,9 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
/* Apply ----------------------------------------------- */
/* Apply brush operation to points in this stroke */
-static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDstroke *gps, GP_BrushApplyCb apply)
+static bool gpsculpt_brush_do_stroke(
+ tGP_BrushEditData *gso, bGPDstroke *gps, bool parented,
+ float diff_mat[4][4], GP_BrushApplyCb apply)
{
GP_SpaceConversion *gsc = &gso->gsc;
rcti *rect = &gso->brush_rect;
@@ -1111,9 +1211,16 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDstroke *gps, GP
int i;
bool include_last = false;
bool changed = false;
-
+
if (gps->totpoints == 1) {
- gp_point_to_xy(gsc, gps, gps->points, &pc1[0], &pc1[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]);
+ }
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
@@ -1140,10 +1247,20 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDstroke *gps, GP
continue;
}
}
-
- gp_point_to_xy(gsc, gps, pt1, &pc1[0], &pc1[1]);
- gp_point_to_xy(gsc, gps, pt2, &pc2[0], &pc2[1]);
-
+ 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]);
+ }
+
+
/* Check that point segment of the boundbox of the selection stroke */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1])))
@@ -1228,76 +1345,105 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
/* Find visible strokes, and perform operations on those if hit */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ float diff_mat[4][4];
+ bool parented = false;
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- switch (gso->brush_type) {
- case GP_EDITBRUSH_TYPE_SMOOTH: /* Smooth strokes */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_smooth_apply);
- break;
- }
-
- case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_thickness_apply);
- break;
+ /* calculate difference matrix if parent object */
+ if (gpl->parent != NULL) {
+ ED_gpencil_parent_location(gpl, diff_mat);
+ parented = true;
+ }
+ else {
+ parented = false;
+ }
+
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+ 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;
}
-
- 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, gp_brush_grab_store_points);
+
+ 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;
}
- else {
- /* Apply effect to the stored points */
- gp_brush_grab_apply_cached(gso, gps);
- changed |= true;
+
+ case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_thickness_apply);
+ break;
}
- break;
- }
-
- case GP_EDITBRUSH_TYPE_PUSH: /* Push points */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_push_apply);
- break;
- }
-
- case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_pinch_apply);
- break;
- }
-
- case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_twist_apply);
- break;
+
+ case GP_EDITBRUSH_TYPE_STRENGTH: /* Adjust stroke color strength */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, parented, 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, parented, diff_mat, gp_brush_grab_store_points);
+ }
+ else {
+ /* Apply effect to the stored points */
+ gp_brush_grab_apply_cached(gso, gps, parented, diff_mat);
+ changed |= true;
+ }
+ 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;
+ }
+
+ 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;
}
-
- case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Apply jitter */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_randomize_apply);
- break;
+ /* Triangulation must be calculated if changed */
+ if (changed) {
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
}
-
- 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;
}
}
CTX_DATA_END;
-
+
return changed;
}
@@ -1441,6 +1587,11 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve
needs_timer = true;
break;
+ case GP_EDITBRUSH_TYPE_STRENGTH:
+ brush_rate = 0.01f; // XXX: hardcoded
+ needs_timer = true;
+ break;
+
case GP_EDITBRUSH_TYPE_PINCH:
brush_rate = 0.001f; // XXX: hardcoded
needs_timer = true;
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index c47985ebc1b..c502ed1aa83 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -142,12 +142,31 @@ static EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRN
/* convert the coordinates from the given stroke point into 3d-coordinates
* - assumes that the active space is the 3D-View
*/
-static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoint *pt, float p3d[3], rctf *subrect)
+static void gp_strokepoint_convertcoords(
+ bContext *C, 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);
-
+ 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);
+ }
+
+
if (gps->flag & GP_STROKE_3DSPACE) {
/* directly use 3d-coordinates */
copy_v3_v3(p3d, &pt->x);
@@ -628,7 +647,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, gps, gps->points, p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
if (prev_bp) {
interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
if (do_gtd) {
@@ -649,7 +668,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, gps, gps->points + 1, next_p, subrect);
+ gp_strokepoint_convertcoords(C, 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);
@@ -670,9 +689,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, gps, gps->points, p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
+ gp_strokepoint_convertcoords(C, 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);
@@ -701,10 +720,10 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
i++, pt++, bp++)
{
float p[3];
- float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
+ float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC;
/* get coordinates to add at */
- gp_strokepoint_convertcoords(C, gps, pt, p, subrect);
+ gp_strokepoint_convertcoords(C, 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);
@@ -816,12 +835,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, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
if (tot > 1) {
- gp_strokepoint_convertcoords(C, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
}
if (stitch && tot > 2) {
- gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
}
}
@@ -940,7 +959,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 * gpl->thickness * WIDTH_CORR_FAC;
+ float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC;
if (i || old_nbezt) {
interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
@@ -964,7 +983,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, gps, pt + 2, p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
}
prev_bezt = bezt;
@@ -1104,7 +1123,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
struct Main *bmain = CTX_data_main(C);
View3D *v3d = CTX_wm_view3d(C); /* may be NULL */
Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
bGPDstroke *gps, *prev_gps = NULL;
Object *ob;
Curve *cu;
@@ -1216,7 +1235,7 @@ static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOpe
int i;
bool valid = true;
- if (!gpl || !(gpf = gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first))
+ if (!gpl || !(gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first))
return false;
do {
@@ -1273,8 +1292,8 @@ static int gp_convert_poll(bContext *C)
* and if we are not in edit mode!
*/
return ((sa && sa->spacetype == SPACE_VIEW3D) &&
- (gpl = gpencil_layer_getactive(gpd)) &&
- (gpf = gpencil_layer_getframe(gpl, CFRA, 0)) &&
+ (gpl = BKE_gpencil_layer_getactive(gpd)) &&
+ (gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0)) &&
(gpf->strokes.first) &&
(scene->obedit == NULL));
}
@@ -1283,7 +1302,7 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op)
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data");
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
Scene *scene = CTX_data_scene(C);
const int mode = RNA_enum_get(op->ptr, "type");
const bool norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights");
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 746497f0ff5..876f873e5fa 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2008, Blender Foundation, Joshua Leung
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -40,6 +40,8 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
#include "BLT_translation.h"
@@ -57,6 +59,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_colortools.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -72,6 +75,8 @@
#include "gpencil_intern.h"
+/* maximum sizes of gp-session buffer */
+#define GP_STROKE_BUFFER_MAX 5000
/* ************************************************ */
/* Datablock Operators */
@@ -92,7 +97,7 @@ static int gp_data_add_exec(bContext *C, wmOperator *op)
bGPdata *gpd = (*gpd_ptr);
id_us_min(&gpd->id);
- *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
+ *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
}
/* notifiers */
@@ -179,10 +184,10 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
if (*gpd_ptr == NULL)
- *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
+ *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
/* add new layer now */
- gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -209,7 +214,7 @@ void GPENCIL_OT_layer_add(wmOperatorType *ot)
static int gp_layer_remove_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
/* sanity checks */
if (ELEM(NULL, gpd, gpl))
@@ -225,12 +230,12 @@ static int gp_layer_remove_exec(bContext *C, wmOperator *op)
* - if this is the only layer, this naturally becomes NULL
*/
if (gpl->prev)
- gpencil_layer_setactive(gpd, gpl->prev);
+ BKE_gpencil_layer_setactive(gpd, gpl->prev);
else
- gpencil_layer_setactive(gpd, gpl->next);
+ BKE_gpencil_layer_setactive(gpd, gpl->next);
/* delete the layer now... */
- gpencil_layer_delete(gpd, gpl);
+ BKE_gpencil_layer_delete(gpd, gpl);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -262,7 +267,7 @@ enum {
static int gp_layer_move_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
int direction = RNA_enum_get(op->ptr, "type");
@@ -316,7 +321,7 @@ void GPENCIL_OT_layer_move(wmOperatorType *ot)
static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
bGPDlayer *new_layer;
/* sanity checks */
@@ -324,12 +329,12 @@ static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* make copy of layer, and add it immediately after the existing layer */
- new_layer = gpencil_layer_duplicate(gpl);
+ new_layer = BKE_gpencil_layer_duplicate(gpl);
BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
/* ensure new layer has a unique name, and is now the active layer */
BLI_uniquename(&gpd->layers, new_layer, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(new_layer->info));
- gpencil_layer_setactive(gpd, new_layer);
+ BKE_gpencil_layer_setactive(gpd, new_layer);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -357,7 +362,7 @@ void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
static int gp_hide_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *layer = gpencil_layer_getactive(gpd);
+ bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
bool unselected = RNA_boolean_get(op->ptr, "unselected");
/* sanity checks */
@@ -525,7 +530,7 @@ void GPENCIL_OT_unlock_all(wmOperatorType *ot)
static int gp_isolate_layer_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *layer = gpencil_layer_getactive(gpd);
+ bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
bGPDlayer *gpl;
int flags = GP_LAYER_LOCKED;
bool isolate = false;
@@ -596,6 +601,61 @@ void GPENCIL_OT_layer_isolate(wmOperatorType *ot)
"In addition to toggling the editability, also affect the visibility");
}
+/* ********************** Merge Layer with the next layer **************************** */
+
+static int gp_merge_layer_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl_current = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl_next = gpl_current->next;
+
+ if (ELEM(NULL, gpd, gpl_current, gpl_next)) {
+ BKE_report(op->reports, RPT_ERROR, "No layers to merge");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Collect frames of gpl_current in hash table to avoid O(n^2) lookups */
+ GHash *gh_frames_cur = BLI_ghash_int_new_ex(__func__, 64);
+ for (bGPDframe *gpf = gpl_current->frames.first; gpf; gpf = gpf->next) {
+ BLI_ghash_insert(gh_frames_cur, SET_INT_IN_POINTER(gpf->framenum), gpf);
+ }
+
+ /* read all frames from next layer */
+ for (bGPDframe *gpf = gpl_next->frames.first; gpf; gpf = gpf->next) {
+ /* try to find frame in active layer */
+ bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, SET_INT_IN_POINTER(gpf->framenum));
+ if (!frame) {
+ /* nothing found, create new */
+ frame = BKE_gpencil_frame_addnew(gpl_current, gpf->framenum);
+ }
+ /* 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 */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_merge(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Merge Down";
+ ot->idname = "GPENCIL_OT_layer_merge";
+ ot->description = "Merge the current layer with the layer below";
+
+ /* callbacks */
+ ot->exec = gp_merge_layer_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ********************** Change Layer ***************************** */
static int gp_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
@@ -621,7 +681,7 @@ static int gp_layer_change_exec(bContext *C, wmOperator *op)
/* Get layer or create new one */
if (layer_num == -1) {
/* Create layer */
- gpl = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
}
else {
/* Try to get layer */
@@ -634,7 +694,7 @@ static int gp_layer_change_exec(bContext *C, wmOperator *op)
}
/* Set active layer */
- gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_setactive(gpd, gpl);
/* updates */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -663,3 +723,1741 @@ void GPENCIL_OT_layer_change(wmOperatorType *ot)
}
/* ************************************************ */
+
+/* ******************* Arrange Stroke Up/Down in drawing order ************************** */
+
+enum {
+ GP_STROKE_MOVE_UP = -1,
+ GP_STROKE_MOVE_DOWN = 1,
+ GP_STROKE_MOVE_TOP = 2,
+ GP_STROKE_MOVE_BOTTOM = 3
+};
+
+static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDstroke *gps;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl, gpl->actframe)) {
+ 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) {
+ BKE_report(op->reports, RPT_ERROR, "Some selected stroke is already on top");
+ return OPERATOR_CANCELLED;
+ }
+ }
+ /* some stroke is already at botom */
+ if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) {
+ if (gps == gpf->strokes.first) {
+ BKE_report(op->reports, RPT_ERROR, "Some selected stroke is already on bottom");
+ return OPERATOR_CANCELLED;
+ }
+ }
+ /* 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_insertlinkafter(&gpf->strokes, gpf->strokes.last, gps);
+ }
+ break;
+ /* Bring Forward */
+ case GP_STROKE_MOVE_UP:
+ for (LinkData *link = selected.last; link; link = link->prev) {
+ gps = link->data;
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_insertlinkafter(&gpf->strokes, gps->next, gps);
+ }
+ break;
+ /* Send Backward */
+ case GP_STROKE_MOVE_DOWN:
+ for (LinkData *link = selected.first; link; link = link->next) {
+ gps = link->data;
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_insertlinkbefore(&gpf->strokes, gps->prev, gps);
+ }
+ 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_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
+ }
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_arrange(wmOperatorType *ot)
+{
+ static EnumPropertyItem slot_move[] = {
+ {GP_STROKE_MOVE_UP, "UP", 0, "Bring Forward", ""},
+ {GP_STROKE_MOVE_DOWN, "DOWN", 0, "Send Backward", ""},
+ {GP_STROKE_MOVE_TOP, "TOP", 0, "Bring to Front", ""},
+ {GP_STROKE_MOVE_BOTTOM, "BOTTOM", 0, "Send to Back", ""},
+ {0, NULL, 0, NULL, NULL }
+ };
+
+ /* identifiers */
+ ot->name = "Arrange Stroke";
+ ot->idname = "GPENCIL_OT_stroke_arrange";
+ ot->description = "Arrange selected strokes up/down in the drawing order of the active layer";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_arrange_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ 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;
+
+ /* 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)) {
+ 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;
+
+ /* asign new color (only if different) */
+ if (STREQ(gps->colorname, color->info) == false) {
+ strcpy(gps->colorname, color->info);
+ gps->flag |= GP_STROKE_RECALC_COLOR;
+ }
+ }
+ }
+ }
+ }
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_change_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Stroke Color";
+ ot->idname = "GPENCIL_OT_stroke_change_color";
+ ot->description = "Move selected strokes to active color";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_change_color_exec;
+ ot->poll = gp_active_layer_poll;
+}
+
+/* ******************* Lock color of non selected Strokes colors ************************** */
+
+static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette;
+
+ /* 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;
+ }
+
+ /* loop all selected strokes and unlock any color */
+ 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;
+ }
+ /* unlock color */
+ if (gps->palcolor != NULL) {
+ gps->palcolor->flag &= ~PC_COLOR_LOCKED;
+ }
+ }
+ }
+ }
+ }
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Lock Unused Colors";
+ ot->idname = "GPENCIL_OT_stroke_lock_color";
+ ot->description = "Lock any color not used in any selected stroke";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_lock_color_exec;
+ ot->poll = gp_active_layer_poll;
+}
+
+/* ******************* Apply layer thickness change to Strokes ************************** */
+
+static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl, gpl->frames.first))
+ return OPERATOR_CANCELLED;
+
+ /* loop all strokes */
+ 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;
+ }
+ }
+ /* clear value */
+ gpl->thickness = 0.0f;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_apply_thickness(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Apply Stroke Thickness";
+ ot->idname = "GPENCIL_OT_stroke_apply_thickness";
+ ot->description = "Apply the thickness change of the layer to its strokes";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_apply_thickness_exec;
+ ot->poll = gp_active_layer_poll;
+}
+
+/* ******************* Close Strokes ************************** */
+
+enum {
+ GP_STROKE_CYCLIC_CLOSE = 1,
+ GP_STROKE_CYCLIC_OPEN = 2,
+ GP_STROKE_CYCLIC_TOGGLE = 3
+};
+
+static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* loop all selected strokes */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
+ bGPDpalettecolor *palcolor = gps->palcolor;
+
+ /* 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))
+ continue;
+
+ switch (type) {
+ case GP_STROKE_CYCLIC_CLOSE:
+ /* Close all (enable) */
+ gps->flag |= GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_OPEN:
+ /* Open all (disable) */
+ gps->flag &= ~GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_TOGGLE:
+ /* Just toggle flag... */
+ gps->flag ^= GP_STROKE_CYCLIC;
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+/**
+ * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
+ * option to force opened/closed strokes instead of just toggle behavior.
+ */
+void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
+{
+ static EnumPropertyItem cyclic_type[] = {
+ {GP_STROKE_CYCLIC_CLOSE, "CLOSE", 0, "Close all", ""},
+ {GP_STROKE_CYCLIC_OPEN, "OPEN", 0, "Open all", ""},
+ {GP_STROKE_CYCLIC_TOGGLE, "TOGGLE", 0, "Toggle", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Set Cyclical State";
+ ot->idname = "GPENCIL_OT_stroke_cyclical_set";
+ ot->description = "Close or open the selected stroke adding an edge from last to first point";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_cyclical_set_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", "");
+}
+
+/* ******************* Stroke join ************************** */
+
+/* Helper: flip stroke */
+static void gpencil_flip_stroke(bGPDstroke *gps)
+{
+ bGPDspoint pt, *point, *point2;
+ int end = gps->totpoints - 1;
+
+ for (int i = 0; i < gps->totpoints / 2; i++) {
+ /* save first point */
+ point = &gps->points[i];
+ pt.x = point->x;
+ pt.y = point->y;
+ pt.z = point->z;
+ pt.flag = point->flag;
+ pt.pressure = point->pressure;
+ pt.strength = point->strength;
+ pt.time = point->time;
+
+ /* replace first point with last point */
+ point2 = &gps->points[end];
+ point->x = point2->x;
+ point->y = point2->y;
+ point->z = point2->z;
+ point->flag = point2->flag;
+ point->pressure = point2->pressure;
+ point->strength = point2->strength;
+ point->time = point2->time;
+
+ /* replace last point with first saved before */
+ point = &gps->points[end];
+ point->x = pt.x;
+ point->y = pt.y;
+ point->z = pt.z;
+ point->flag = pt.flag;
+ point->pressure = pt.pressure;
+ point->strength = pt.strength;
+ point->time = pt.time;
+
+ end--;
+ }
+}
+
+/* Helper: copy point between strokes */
+static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float delta[3],
+ float pressure, float strength, float deltatime)
+{
+ bGPDspoint *newpoint;
+
+ gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ gps->totpoints++;
+
+ newpoint = &gps->points[gps->totpoints - 1];
+ newpoint->x = point->x * delta[0];
+ newpoint->y = point->y * delta[1];
+ newpoint->z = point->z * delta[2];
+ newpoint->flag = point->flag;
+ newpoint->pressure = pressure;
+ newpoint->strength = strength;
+ newpoint->time = point->time + deltatime;
+}
+
+/* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */
+static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, const bool leave_gaps)
+{
+ bGPDspoint point, *pt;
+ int i;
+ float delta[3] = {1.0f, 1.0f, 1.0f};
+ float deltatime = 0.0f;
+
+ /* sanity checks */
+ if (ELEM(NULL, gps_a, gps_b))
+ return;
+
+ if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0))
+ return;
+
+ /* define start and end points of each stroke */
+ float sa[3], sb[3], ea[3], eb[3];
+ pt = &gps_a->points[0];
+ copy_v3_v3(sa, &pt->x);
+
+ pt = &gps_a->points[gps_a->totpoints - 1];
+ copy_v3_v3(ea, &pt->x);
+
+ pt = &gps_b->points[0];
+ copy_v3_v3(sb, &pt->x);
+
+ pt = &gps_b->points[gps_b->totpoints - 1];
+ copy_v3_v3(eb, &pt->x);
+
+ /* review if need flip stroke B */
+ float ea_sb = len_squared_v3v3(ea, sb);
+ float ea_eb = len_squared_v3v3(ea, eb);
+ /* flip if distance to end point is shorter */
+ if (ea_eb < ea_sb) {
+ gpencil_flip_stroke(gps_b);
+ }
+
+ /* don't visibly link the first and last points? */
+ if (leave_gaps) {
+ /* 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);
+
+ /* 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);
+ }
+
+ /* 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);
+ }
+ }
+}
+
+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);
+
+ bGPDframe *gpf_a = NULL;
+ bGPDstroke *stroke_a = NULL;
+ bGPDstroke *stroke_b = NULL;
+ bGPDstroke *new_stroke = NULL;
+
+ const int type = RNA_enum_get(op->ptr, "type");
+ const bool leave_gaps = RNA_boolean_get(op->ptr, "leave_gaps");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ if (activegpl->flag & GP_LAYER_LOCKED)
+ return OPERATOR_CANCELLED;
+
+ BLI_assert(ELEM(type, GP_STROKE_JOIN, GP_STROKE_JOINCOPY));
+
+
+ /* read all selected strokes */
+ bool first = false;
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf = gpl->actframe;
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ 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;
+ }
+ /* to join strokes, cyclic must be disabled */
+ gps->flag &= ~GP_STROKE_CYCLIC;
+ /* saves first frame and stroke */
+ if (!first) {
+ first = true;
+ gpf_a = gpf;
+ stroke_a = gps;
+ }
+ else {
+ stroke_b = gps;
+ /* create a new stroke if was not created before (only created if something to join) */
+ if (new_stroke == NULL) {
+ new_stroke = MEM_dupallocN(stroke_a);
+ new_stroke->points = MEM_dupallocN(stroke_a->points);
+ 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;
+ strcpy(new_stroke->colorname, palcolor->info);
+ new_stroke->flag |= GP_STROKE_RECALC_COLOR;
+ }
+ }
+ /* join new_stroke and stroke B. New stroke will contain all the previous data */
+ gpencil_stroke_join_strokes(new_stroke, stroke_b, leave_gaps);
+
+ /* if join only, delete old strokes */
+ if (type == GP_STROKE_JOIN) {
+ if (stroke_a) {
+ BLI_insertlinkbefore(&gpf_a->strokes, stroke_a, new_stroke);
+ BLI_remlink(&gpf->strokes, stroke_a);
+ BKE_gpencil_free_stroke(stroke_a);
+ stroke_a = NULL;
+ }
+ if (stroke_b) {
+ BLI_remlink(&gpf->strokes, stroke_b);
+ BKE_gpencil_free_stroke(stroke_b);
+ stroke_b = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+ /* add new stroke if was not added before */
+ if (type == GP_STROKE_JOINCOPY) {
+ if (new_stroke) {
+ /* Add a new frame if needed */
+ if (activegpl->actframe == NULL)
+ activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum);
+
+ BLI_addtail(&activegpl->actframe->strokes, new_stroke);
+ }
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_join(wmOperatorType *ot)
+{
+ static EnumPropertyItem join_type[] = {
+ {GP_STROKE_JOIN, "JOIN", 0, "Join", ""},
+ {GP_STROKE_JOINCOPY, "JOINCOPY", 0, "Join and Copy", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Join Strokes";
+ ot->idname = "GPENCIL_OT_stroke_join";
+ ot->description = "Join selected strokes (optionally as new stroke)";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_join_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", join_type, GP_STROKE_JOIN, "Type", "");
+ RNA_def_boolean(ot->srna, "leave_gaps", false, "Leave Gaps", "Leave gaps between joined strokes instead of linking them");
+}
+
+/* ******************* Stroke flip ************************** */
+
+static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* read all selected strokes */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf = gpl->actframe;
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ 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;
+ }
+ /* flip stroke */
+ gpencil_flip_stroke(gps);
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flip Stroke";
+ ot->idname = "GPENCIL_OT_stroke_flip";
+ ot->description = "Change direction of the points of the selected strokes";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_flip_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)
+{
+ 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);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_add(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 datablock";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_brush_add_exec;
+ ot->poll = gp_add_poll;
+}
+
+/* ******************* Remove Active Brush ************************* */
+
+static int gp_brush_remove_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;
+
+ if (BLI_listbase_count(&ts->gp_brushes) < 2) {
+ BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a brush. Unable to delete brush");
+ return OPERATOR_CANCELLED;
+ }
+
+
+ /* 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);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_remove(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;
+
+ /* callbacks */
+ ot->exec = gp_brush_remove_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);
+
+ return OPERATOR_INTERFACE;
+}
+
+static int gp_brush_change_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);
+ }
+ 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;
+ }
+ }
+
+ /* Set active brush */
+ BKE_gpencil_brush_setactive(ts, brush);
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_change(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Brush";
+ ot->idname = "GPENCIL_OT_brush_change";
+ ot->description = "Change active Grease Pencil drawing brush";
+
+ /* callbacks */
+ ot->invoke = gp_brush_change_invoke;
+ ot->exec = gp_brush_change_exec;
+ ot->poll = gp_active_brush_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);
+}
+
+/* ******************* Move Brush Up/Down ************************** */
+
+enum {
+ GP_BRUSH_MOVE_UP = -1,
+ GP_BRUSH_MOVE_DOWN = 1
+};
+
+static int gp_brush_move_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
+
+ int direction = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, ts, brush)) {
+ 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);
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_move(wmOperatorType *ot)
+{
+ static 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";
+
+ /* api callbacks */
+ ot->exec = gp_brush_move_exec;
+ ot->poll = gp_active_brush_poll;
+
+ /* 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))
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ BKE_gpencil_brush_init_presets(ts);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_presets_create(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";
+
+ /* api callbacks */
+ ot->exec = gp_brush_presets_create_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+}
+
+/* ***************** Copy Brush ************************ */
+
+static int gp_brush_copy_exec(bContext *C, wmOperator *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;
+
+ /* sanity checks */
+ if (ELEM(NULL, brush))
+ 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);
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_copy(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy Brush";
+ ot->idname = "GPENCIL_OT_brush_copy";
+ ot->description = "Copy current Grease Pencil drawing brush";
+
+ /* callbacks */
+ ot->exec = gp_brush_copy_exec;
+ ot->poll = gp_active_brush_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ***************** Select Brush ************************ */
+
+static int gp_brush_select_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(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)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_gpencil_brush_setactive(ts, brush);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Brush";
+ ot->idname = "GPENCIL_OT_brush_select";
+ ot->description = "Select a Grease Pencil drawing brush";
+
+ /* callbacks */
+ ot->exec = gp_brush_select_exec;
+ ot->poll = gp_active_brush_poll;
+
+ /* 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)
+{
+ 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(DATA_("GPencil"));
+
+ /* add new palette now */
+ BKE_gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palette_add(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 datablock";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_palette_add_exec;
+ ot->poll = gp_add_poll;
+}
+
+/* ******************* Remove Active Palette ************************* */
+
+static int gp_palette_remove_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette))
+ return OPERATOR_CANCELLED;
+
+ if (BLI_listbase_count(&gpd->palettes) < 2) {
+ BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a palette. Unable to delete palette");
+ 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);
+
+ /* delete the palette now... */
+ BKE_gpencil_palette_delete(gpd, palette);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palette_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove palette";
+ ot->idname = "GPENCIL_OT_palette_remove";
+ ot->description = "Remove active Grease Pencil palette";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_palette_remove_exec;
+ ot->poll = gp_active_palette_poll;
+}
+
+/* ********************** Change Palette ***************************** */
+
+static int gp_palette_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_palette_change", "palette");
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
+static int gp_palette_change_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDpalette *palette = NULL;
+ int palette_num = RNA_enum_get(op->ptr, "palette");
+
+ /* Get palette or create new one */
+ if (palette_num == -1) {
+ /* Create palette */
+ palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true);
+ }
+ 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;
+ }
+ }
+
+ /* Set active palette */
+ BKE_gpencil_palette_setactive(gpd, palette);
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+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";
+
+ /* callbacks */
+ ot->invoke = gp_palette_change_invoke;
+ ot->exec = gp_palette_change_exec;
+ ot->poll = gp_active_palette_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* 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);
+}
+
+/* ******************* Lock and hide any color non used in current layer ************************** */
+
+static int gp_palette_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ palette = BKE_gpencil_palette_getactive(gpd);
+ if (ELEM(NULL, palette))
+ 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;
+ }
+
+ /* loop all selected strokes and unlock any color used in active layer */
+ 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) && (gpl->flag & GP_LAYER_ACTIVE)) {
+ for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ /* unlock/unhide color if not unlocked before */
+ if (gps->palcolor != NULL) {
+ gps->palcolor->flag &= ~PC_COLOR_LOCKED;
+ gps->palcolor->flag &= ~PC_COLOR_HIDE;
+ }
+ }
+ }
+ }
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palette_lock_layer(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Disable Unused Layer Colors";
+ ot->idname = "GPENCIL_OT_palette_lock_layer";
+ ot->description = "Lock and hide any color not used in any layer";
+
+ /* api callbacks */
+ ot->exec = gp_palette_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)
+{
+ 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(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 datablock";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_palettecolor_add_exec;
+ ot->poll = gp_add_poll;
+}
+
+/* ******************* Remove Active Palette color ************************* */
+
+static int gp_palettecolor_remove_exec(bContext *C, wmOperator *UNUSED(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);
+
+ 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;
+ bool isolate = false;
+
+ if (RNA_boolean_get(op->ptr, "affect_visibility"))
+ flags |= PC_COLOR_HIDE;
+
+ if (ELEM(NULL, gpd, active_color)) {
+ BKE_report(op->reports, RPT_ERROR, "No active color to isolate");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Test whether to isolate or clear all flags */
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ /* Skip if this is the active one */
+ if (palcolor == active_color)
+ 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) {
+ isolate = true;
+ break;
+ }
+ }
+
+ /* 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)
+ continue;
+ else
+ palcolor->flag |= flags;
+ }
+ }
+ else {
+ /* Clear flags - Restore everything else */
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ palcolor->flag &= ~flags;
+ }
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_isolate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Isolate Palette Color";
+ ot->idname = "GPENCIL_OT_palettecolor_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;
+
+ /* 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");
+}
+
+/* *********************** Hide Palette colors ******************************** */
+
+static int gp_palettecolor_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);
+
+ bool unselected = RNA_boolean_get(op->ptr, "unselected");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette, palcolor))
+ 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;
+ }
+ }
+ }
+ else {
+ /* hide selected/active */
+ palcolor->flag |= PC_COLOR_HIDE;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hide Color(s)";
+ ot->idname = "GPENCIL_OT_palettecolor_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 */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected colors");
+}
+
+/* ********************** Show All Colors ***************************** */
+
+/* poll callback for showing colors */
+static int 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))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette))
+ return OPERATOR_CANCELLED;
+
+ /* make all colors visible */
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ palcolor->flag &= ~PC_COLOR_HIDE;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_reveal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Show All Colors";
+ ot->idname = "GPENCIL_OT_palettecolor_reveal";
+ ot->description = "Unhide all hidden Grease Pencil palette colors";
+
+ /* callbacks */
+ ot->exec = gp_palettecolor_reveal_exec;
+ ot->poll = gp_palettecolor_reveal_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ***************** Lock/Unlock All Palette colors ************************ */
+
+static int gp_palettecolor_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))
+ return OPERATOR_CANCELLED;
+
+ /* make all layers non-editable */
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ palcolor->flag |= PC_COLOR_LOCKED;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_lock_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Lock All Colors";
+ ot->idname = "GPENCIL_OT_palettecolor_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 */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* -------------------------- */
+
+static int gp_palettecolor_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;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette))
+ return OPERATOR_CANCELLED;
+
+ /* make all layers editable again*/
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ palcolor->flag &= ~PC_COLOR_LOCKED;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_unlock_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Unlock All Colors";
+ ot->idname = "GPENCIL_OT_palettecolor_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 */
+
+ /* 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 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 */
+
+ /* 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))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette, palcolor))
+ return OPERATOR_CANCELLED;
+
+ /* read all strokes and select*/
+ 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)) {
+ /* verify something to do */
+ 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;
+
+ /* select */
+ if (strcmp(palcolor->info, gps->colorname) == 0) {
+ bGPDspoint *pt;
+ int i;
+
+ gps->flag |= GP_STROKE_SELECT;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ }
+ }
+ }
+ }
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Color";
+ ot->idname = "GPENCIL_OT_palettecolor_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;
+
+ /* 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 ac49a51c716..b298769c6dc 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -125,10 +125,48 @@ static int gp_stroke_edit_poll(bContext *C)
return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
}
+/* ************ 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)
+ return OPERATOR_CANCELLED;
+
+ /* Just toggle alpha... */
+ if (ts->gp_sculpt.alpha > 0.0f) {
+ ts->gp_sculpt.alpha = 0.0f;
+ }
+ else {
+ ts->gp_sculpt.alpha = 1.0f;
+ }
+
+ 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_selection_opacity_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hide Selection";
+ ot->idname = "GPENCIL_OT_selection_opacity_toggle";
+ ot->description = "Hide/Unhide selected points for Grease Pencil strokes setting alpha factor";
+
+ /* callbacks */
+ ot->exec = gpencil_hideselect_toggle_exec;
+ ot->poll = gp_stroke_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+}
+
/* ************** Duplicate Selected Strokes **************** */
/* Make copies of selected point segments in a selected stroke */
-static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes)
+static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, const char *layername)
{
bGPDspoint *pt;
int i;
@@ -169,6 +207,7 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes)
/* make a stupid copy first of the entire stroke (to get the flags too) */
gpsd = MEM_dupallocN(gps);
+ strcpy(gpsd->tmp_layerinfo, layername); /* saves original layer name */
/* initialize triangle memory - will be calculated on next redraw */
gpsd->triangles = NULL;
@@ -216,8 +255,9 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
/* make copies of selected strokes, and deselect these once we're done */
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)
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
+ }
if (gps->flag & GP_STROKE_SELECT) {
if (gps->totpoints == 1) {
@@ -226,8 +266,9 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
/* make direct copies of the stroke and its points */
gpsd = MEM_dupallocN(gps);
+ strcpy(gpsd->tmp_layerinfo, gpl->info);
gpsd->points = MEM_dupallocN(gps->points);
-
+
/* triangle information - will be calculated on next redraw */
gpsd->flag |= GP_STROKE_RECALC_CACHES;
gpsd->triangles = NULL;
@@ -238,7 +279,7 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
}
else {
/* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
- gp_duplicate_points(gps, &new_strokes);
+ gp_duplicate_points(gps, &new_strokes, gpl->info);
}
/* deselect original stroke, or else the originals get moved too
@@ -345,6 +386,7 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
/* make direct copies of the stroke and its points */
gpsd = MEM_dupallocN(gps);
+ strcpy(gpsd->tmp_layerinfo, gpl->info); /* saves original layer name */
gpsd->points = MEM_dupallocN(gps->points);
/* triangles cache - will be recalculated on next redraw */
@@ -358,7 +400,7 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
}
else {
/* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
- gp_duplicate_points(gps, &gp_strokes_copypastebuf);
+ gp_duplicate_points(gps, &gp_strokes_copypastebuf, gpl->info);
}
}
}
@@ -395,13 +437,20 @@ static int gp_strokes_paste_poll(bContext *C)
return (CTX_data_active_gpencil_layer(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf));
}
+enum {
+ GP_COPY_ONLY = -1,
+ GP_COPY_MERGE = 1
+};
+
static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); /* only use active for copy merge */
bGPDframe *gpf;
-
+
+ int type = RNA_enum_get(op->ptr, "type");
+
/* check for various error conditions */
if (gpd == NULL) {
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
@@ -413,9 +462,9 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
}
else if (gpl == NULL) {
/* no active layer - let's just create one */
- gpl = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
}
- else if (gpencil_layer_is_editable(gpl) == false) {
+ else if ((gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_MERGE)) {
BKE_report(op->reports, RPT_ERROR, "Can not paste strokes when active layer is hidden or locked");
return OPERATOR_CANCELLED;
}
@@ -463,26 +512,34 @@ 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 = gpencil_layer_getframe(gpl, CFRA, true);
- if (gpf) {
bGPDstroke *gps;
-
/* Copy each stroke into the layer */
for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
if (ED_gpencil_stroke_can_use(C, gps)) {
- bGPDstroke *new_stroke = MEM_dupallocN(gps);
-
- new_stroke->points = MEM_dupallocN(gps->points);
-
- new_stroke->flag |= GP_STROKE_RECALC_CACHES;
- new_stroke->triangles = NULL;
-
- new_stroke->next = new_stroke->prev = NULL;
- BLI_addtail(&gpf->strokes, new_stroke);
+ /* need to verify if layer exist nad frame */
+ if (type != GP_COPY_MERGE) {
+ gpl = BLI_findstring(&gpd->layers, gps->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);
+ }
+ }
+ gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
+ if (gpf) {
+ bGPDstroke *new_stroke = MEM_dupallocN(gps);
+ new_stroke->tmp_layerinfo[0] = '\0';
+
+ new_stroke->points = MEM_dupallocN(gps->points);
+
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ new_stroke->triangles = NULL;
+
+ new_stroke->next = new_stroke->prev = NULL;
+ BLI_addtail(&gpf->strokes, new_stroke);
+ }
}
}
- }
/* updates */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -492,10 +549,16 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_paste(wmOperatorType *ot)
{
+ static EnumPropertyItem copy_type[] = {
+ {GP_COPY_ONLY, "COPY", 0, "Copy", ""},
+ {GP_COPY_MERGE, "MERGE", 0, "Merge", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
ot->name = "Paste Strokes";
ot->idname = "GPENCIL_OT_paste";
- ot->description = "Paste previously copied strokes into active layer";
+ ot->description = "Paste previously copied strokes or copy and merge in active layer";
/* callbacks */
ot->exec = gp_strokes_paste_exec;
@@ -503,6 +566,8 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", copy_type, 0, "Type", "");
}
/* ******************* Move To Layer ****************************** */
@@ -532,7 +597,7 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
/* Get layer or create new one */
if (layer_num == -1) {
/* Create layer */
- target_layer = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ target_layer = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
}
else {
/* Try to get layer */
@@ -577,7 +642,7 @@ 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 = gpencil_layer_getframe(target_layer, CFRA, true);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(target_layer, CFRA, true);
BLI_movelisttolist(&gpf->strokes, &strokes);
BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL));
@@ -614,7 +679,7 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
static int gp_actframe_delete_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
/* only if there's an active layer with an active frame */
return (gpl && gpl->actframe);
@@ -625,8 +690,8 @@ 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 = gpencil_layer_getactive(gpd);
- bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
/* if there's no existing Grease-Pencil data there, add some */
if (gpd == NULL) {
@@ -639,7 +704,7 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
}
/* delete it... */
- gpencil_layer_delframe(gpl, gpf);
+ BKE_gpencil_layer_delframe(gpl, gpf);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -681,13 +746,13 @@ static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
/* try to get the "active" frame - but only if it actually occurs on this frame */
- bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
if (gpf == NULL)
continue;
/* delete it... */
- gpencil_layer_delframe(gpl, gpf);
+ BKE_gpencil_layer_delframe(gpl, gpf);
/* we successfully modified something */
success = true;
@@ -1069,7 +1134,7 @@ void GPENCIL_OT_delete(wmOperatorType *ot)
};
/* identifiers */
- ot->name = "Delete...";
+ ot->name = "Delete";
ot->idname = "GPENCIL_OT_delete";
ot->description = "Delete selected Grease Pencil strokes, vertices, or frames";
@@ -1124,25 +1189,65 @@ static int gp_snap_poll(bContext *C)
static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
{
RegionView3D *rv3d = CTX_wm_region_data(C);
- float gridf = rv3d->gridview;
+ const float gridf = rv3d->gridview;
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- bGPDspoint *pt;
- int i;
-
- // TOOD: 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) {
- 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);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ float diff_mat[4][4];
+
+ 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)) {
+
+ /* calculate difference matrix if parent object */
+ if (gpl->parent != NULL) {
+ ED_gpencil_parent_location(gpl, diff_mat);
+ }
+
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+ 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;
+ }
+
+ bGPDspoint *pt;
+ int i;
+
+ // TOOD: 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);
+
+ 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);
+ }
+
+ }
+ }
+
}
}
}
- CTX_DATA_END;
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1169,41 +1274,68 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
-
+
const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
const float *cursor_global = ED_view3d_cursor3d_get(scene, v3d);
-
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- bGPDspoint *pt;
- int i;
-
- /* only continue if this stroke is selected (editable doesn't guarantee this)... */
- if ((gps->flag & GP_STROKE_SELECT) == 0)
- continue;
-
- if (use_offset) {
- float offset[3];
-
- /* compute offset from first point of stroke to cursor */
- /* TODO: Allow using midpoint instead? */
- sub_v3_v3v3(offset, cursor_global, &gps->points->x);
-
- /* apply offset to all points in the stroke */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- add_v3_v3(&pt->x, offset);
+
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ float diff_mat[4][4];
+
+ 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)) {
+
+ /* calculate difference matrix if parent object */
+ if (gpl->parent != NULL) {
+ ED_gpencil_parent_location(gpl, diff_mat);
}
- }
- else {
- /* affect each selected point */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- copy_v3_v3(&pt->x, cursor_global);
+
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+ 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;
+ }
+
+ bGPDspoint *pt;
+ int i;
+
+ /* only continue if this stroke is selected (editable doesn't guarantee this)... */
+ if ((gps->flag & GP_STROKE_SELECT) == 0)
+ continue;
+
+ if (use_offset) {
+ float offset[3];
+
+ /* compute offset from first point of stroke to cursor */
+ /* TODO: Allow using midpoint instead? */
+ sub_v3_v3v3(offset, cursor_global, &gps->points->x);
+
+ /* apply offset to all points in the stroke */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ add_v3_v3(&pt->x, offset);
+ }
+ }
+ else {
+ /* affect each selected point */
+ 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);
+ }
+ }
+ }
}
+
+
}
}
}
- CTX_DATA_END;
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1243,24 +1375,57 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
INIT_MINMAX(min, max);
/* calculate midpoints from selected points */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- bGPDspoint *pt;
- int i;
-
- /* only continue if this stroke is selected (editable doesn't guarantee this)... */
- if ((gps->flag & GP_STROKE_SELECT) == 0)
- continue;
-
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- add_v3_v3(centroid, &pt->x);
- minmax_v3v3_v3(min, max, &pt->x);
- count++;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ float diff_mat[4][4];
+
+ 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)) {
+
+ /* calculate difference matrix if parent object */
+ if (gpl->parent != NULL) {
+ ED_gpencil_parent_location(gpl, diff_mat);
+ }
+
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+ 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;
+ }
+
+ bGPDspoint *pt;
+ int i;
+
+ /* only continue if this stroke is selected (editable doesn't guarantee this)... */
+ if ((gps->flag & GP_STROKE_SELECT) == 0)
+ continue;
+
+ 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);
+
+ add_v3_v3(centroid, fpt);
+ minmax_v3v3_v3(min, max, fpt);
+ }
+ count++;
+ }
+ }
+
}
}
}
- CTX_DATA_END;
if (v3d->around == V3D_AROUND_CENTER_MEAN && count) {
mul_v3_fl(centroid, 1.0f / (float)count);
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 53fb33eeb9b..f37fba4212d 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -101,6 +101,23 @@ void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct
int *r_x, int *r_y);
/**
+ * Convert point to parent space
+ *
+ * \param pt Original point
+ * \param diff_mat Matrix with the difference between original parent matrix
+ * \param[out] r_pt Pointer to new point after apply matrix
+ */
+void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt);
+/**
+ * Change points position relative to parent object
+ */
+void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps);
+/**
+ * Change point position relative to parent object
+ */
+void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt);
+
+/**
* Convert a screenspace point to a 3D Grease Pencil coordinate.
*
* For use with editing tools where it is easier to perform the operations in 2D,
@@ -116,6 +133,10 @@ bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, struct Scene *scene, const float
int gp_add_poll(struct bContext *C);
int gp_active_layer_poll(struct bContext *C);
+int gp_active_brush_poll(struct bContext *C);
+int gp_active_palette_poll(struct bContext *C);
+int gp_active_palettecolor_poll(struct bContext *C);
+int gp_brush_crt_presets_poll(bContext *C);
/* Copy/Paste Buffer --------------------------------- */
/* gpencil_edit.c */
@@ -137,17 +158,47 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke
bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure);
/**
+* 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);
+
+/**
+* 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);
+
+/**
* Subdivide a stroke once, by adding points at the midpoint between each pair of points
* \param gps Stroke data
* \param new_totpoints Total number of points (after subdividing)
*/
void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints);
+/**
+* Add randomness to stroke
+* \param gps Stroke data
+* \param brsuh Brush data
+*/
+void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush);
+
/* Layers Enums -------------------------------------- */
struct EnumPropertyItem *ED_gpencil_layers_enum_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
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 */
+EnumPropertyItem *ED_gpencil_brushes_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
+ bool *r_free);
+
+/* Enums of GP palettes */
+EnumPropertyItem *ED_gpencil_palettes_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
+ bool *r_free);
/* ***************************************************** */
/* Operator Defines */
@@ -155,7 +206,7 @@ struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bContext *
void GPENCIL_OT_draw(struct wmOperatorType *ot);
-/* Paint Modes for operator*/
+/* Paint Modes for operator */
typedef enum eGPencil_PaintModes {
GP_PAINTMODE_DRAW = 0,
GP_PAINTMODE_ERASER,
@@ -166,6 +217,7 @@ typedef enum eGPencil_PaintModes {
/* stroke editing ----- */
void GPENCIL_OT_editmode_toggle(struct wmOperatorType *ot);
+void GPENCIL_OT_selection_opacity_toggle(struct wmOperatorType *ot);
void GPENCIL_OT_select(struct wmOperatorType *ot);
void GPENCIL_OT_select_all(struct wmOperatorType *ot);
@@ -216,12 +268,50 @@ void GPENCIL_OT_lock_all(struct wmOperatorType *ot);
void GPENCIL_OT_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_merge(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_convert(struct wmOperatorType *ot);
+enum {
+ GP_STROKE_JOIN = -1,
+ GP_STROKE_JOINCOPY = 1
+};
+
+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);
+void GPENCIL_OT_stroke_apply_thickness(struct wmOperatorType *ot);
+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_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);
+
/* undo stack ---------- */
void gpencil_undo_init(struct bGPdata *gpd);
@@ -273,4 +363,39 @@ typedef enum ACTCONT_TYPES {
ACTCONT_GPENCIL
} ACTCONT_TYPES;
+/**
+* Iterate over all editable strokes in the current context,
+* stopping on each usable layer + stroke pair (i.e. gpl and gps)
+* to perform some operations on the stroke.
+*
+* \param gpl The identifier to use for the layer of the stroke being processed.
+* Choose a suitable value to avoid name clashes.
+* \param gps The identifier to use for current stroke being processed.
+* Choose a suitable value to avoid name clashes.
+*/
+#define GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) \
+{ \
+ 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 ... */
+
+#define GP_EDITABLE_STROKES_END \
+ } \
+ } \
+ CTX_DATA_END; \
+} (void)0
+
#endif /* __GPENCIL_INTERN_H__ */
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 65ee1122b56..50f4e795d70 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2009, Blender Foundation, Joshua Leung
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -140,8 +140,8 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
* that the only data being edited is that of the Grease Pencil strokes
*/
- /* FKEY = Eraser Radius */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
+ /* 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");
@@ -169,8 +169,8 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
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");
- /* Ctrl-FKEY = Sculpt Brush Size */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
+ /* 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");
@@ -240,6 +240,12 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0);
+ /* join strokes */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_stroke_join", JKEY, KM_PRESS, KM_CTRL, 0);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_stroke_join", JKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "type", GP_STROKE_JOINCOPY);
+
/* copy + paste */
WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
@@ -266,14 +272,37 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "unselected", true);
+
+ WM_keymap_add_item(keymap, "GPENCIL_OT_selection_opacity_toggle", HKEY, KM_PRESS, KM_CTRL, 0);
/* Isolate Layer */
WM_keymap_add_item(keymap, "GPENCIL_OT_layer_isolate", PADASTERKEY, KM_PRESS, 0, 0);
/* Move to Layer */
WM_keymap_add_item(keymap, "GPENCIL_OT_move_to_layer", MKEY, KM_PRESS, 0, 0);
-
-
+
+ /* Select drawing brush using index */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", ONEKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 0);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", TWOKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 1);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", THREEKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 2);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", FOURKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 3);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", FIVEKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 4);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", SIXKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 5);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", SEVENKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 6);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", EIGHTKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 7);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", NINEKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 8);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", ZEROKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 9);
+
/* Transform Tools */
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
@@ -318,7 +347,8 @@ void ED_operatortypes_gpencil(void)
/* Editing (Strokes) ------------ */
WM_operatortype_append(GPENCIL_OT_editmode_toggle);
-
+ WM_operatortype_append(GPENCIL_OT_selection_opacity_toggle);
+
WM_operatortype_append(GPENCIL_OT_select);
WM_operatortype_append(GPENCIL_OT_select_all);
WM_operatortype_append(GPENCIL_OT_select_circle);
@@ -362,12 +392,44 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_lock_all);
WM_operatortype_append(GPENCIL_OT_unlock_all);
WM_operatortype_append(GPENCIL_OT_layer_isolate);
-
+ WM_operatortype_append(GPENCIL_OT_layer_merge);
+
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
WM_operatortype_append(GPENCIL_OT_convert);
+ WM_operatortype_append(GPENCIL_OT_stroke_arrange);
+ WM_operatortype_append(GPENCIL_OT_stroke_change_color);
+ WM_operatortype_append(GPENCIL_OT_stroke_lock_color);
+ WM_operatortype_append(GPENCIL_OT_stroke_apply_thickness);
+ WM_operatortype_append(GPENCIL_OT_stroke_cyclical_set);
+ WM_operatortype_append(GPENCIL_OT_stroke_join);
+ WM_operatortype_append(GPENCIL_OT_stroke_flip);
+
+ 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);
+
/* Editing (Time) --------------- */
}
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index a570d586f50..e7e39a85792 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2008, Blender Foundation, Joshua Leung
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -39,21 +39,26 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_rand.h"
#include "BLT_translation.h"
#include "PIL_time.h"
+#include "BKE_main.h"
+#include "BKE_paint.h"
#include "BKE_gpencil.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_tracking.h"
+#include "BKE_colortools.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"
@@ -151,6 +156,10 @@ typedef struct tGPsdata {
float custom_color[4]; /* custom color - hack for enforcing a particular color for track/mask editing */
void *erasercursor; /* radial cursor data for drawing eraser */
+
+ bGPDpalettecolor *palettecolor; /* current palette color */
+ bGPDbrush *brush; /* current drawing brush */
+ short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */
} tGPsdata;
/* ------ */
@@ -333,10 +342,90 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3]
}
}
+/* apply jitter to stroke */
+static void gp_brush_jitter(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const int mval[2], int r_mval[2])
+{
+ 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;
+ }
+ const float exfactor = (brush->draw_jitter + 2.0f) * (brush->draw_jitter + 2.0f); /* exponential value */
+ const float fac = BLI_frand() * 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) {
+ mvec[0] = (float)(mval[0] - (pt - 1)->x);
+ mvec[1] = (float)(mval[1] - (pt - 1)->y);
+ normalize_v2(mvec);
+ }
+ else {
+ mvec[0] = 0.0f;
+ mvec[1] = 0.0f;
+ }
+ /* rotate mvec by 90 degrees... */
+ svec[0] = -mvec[1];
+ svec[1] = mvec[0];
+ /* scale the displacement by the random, and apply */
+ if (BLI_frand() > 0.5f) {
+ mul_v2_fl(svec, -fac);
+ }
+ else {
+ mul_v2_fl(svec, fac);
+ }
+
+ r_mval[0] = mval[0] + svec[0];
+ r_mval[1] = mval[1] + svec[1];
+
+}
+
+/* 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])
+{
+ float mvec[2];
+ float sen = brush->draw_angle_factor; /* sensitivity */;
+ float fac;
+ float mpressure;
+
+ float angle = brush->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) {
+ mvec[0] = (float)(mval[0] - (pt - 1)->x);
+ mvec[1] = (float)(mval[1] - (pt - 1)->y);
+ normalize_v2(mvec);
+
+ /* uses > 1.0f to get a smooth transition in first point */
+ fac = 1.4f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
+ (pt - 1)->pressure = (pt - 1)->pressure - (sen * fac);
+
+ CLAMP((pt - 1)->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
+ }
+
+ /* apply from second point */
+ if (gpd->sbuffer_size >= 1) {
+ mvec[0] = (float)(mval[0] - (pt - 1)->x);
+ mvec[1] = (float)(mval[1] - (pt - 1)->y);
+ normalize_v2(mvec);
+
+ fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
+ /* interpolate with previous point for smoother transitions */
+ mpressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f);
+ pt->pressure = mpressure;
+
+ CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
+ }
+
+}
+
/* 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;
tGPspoint *pt;
/* check painting mode */
@@ -349,6 +438,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
/* 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 */
@@ -363,6 +453,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
/* 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) */
@@ -381,8 +472,65 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
pt = ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size);
/* store settings */
- copy_v2_v2_int(&pt->x, mval);
- pt->pressure = pressure;
+ /* pressure */
+ if (brush->flag & GP_BRUSH_USE_PRESSURE) {
+ float curvef = curvemapping_evaluateF(brush->cur_sensitivity, 0, pressure);
+ pt->pressure = curvef * brush->draw_sensitivity;
+ }
+ else {
+ pt->pressure = 1.0f;
+ }
+ /* Apply jitter to position */
+ if (brush->draw_jitter > 0.0f) {
+ int r_mval[2];
+ gp_brush_jitter(gpd, brush, pt, mval, r_mval);
+ copy_v2_v2_int(&pt->x, r_mval);
+ }
+ else {
+ 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 (BLI_frand() > 0.5f) {
+ pt->pressure -= tmp_pressure * brush->draw_random_press * BLI_frand();
+ }
+ else {
+ pt->pressure += tmp_pressure * brush->draw_random_press * BLI_frand();
+ }
+ CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+
+ /* apply angle of stroke to brush size */
+ if (brush->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;
+
+ pt->strength = tmp_pressure * brush->draw_strength;
+ }
+ else {
+ pt->strength = brush->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 (BLI_frand() > 0.5f) {
+ pt->strength -= pt->strength * brush->draw_random_press * BLI_frand();
+ }
+ else {
+ pt->strength += pt->strength * brush->draw_random_press * BLI_frand();
+ }
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+
+ /* point time */
pt->time = (float)(curtime - p->inittime);
/* increment counters */
@@ -395,12 +543,15 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
return GP_STROKEADD_NORMAL;
}
else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
/* get pointer to destination point */
pt = (tGPspoint *)(gpd->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
@@ -433,10 +584,16 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
-
+ /* if parented change position relative to parent object */
+ if (gpl->parent != NULL) {
+ gp_apply_parent_point(gpl, pts);
+ }
/* 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 */
@@ -534,6 +691,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
bGPDstroke *gps;
bGPDspoint *pt;
tGPspoint *ptc;
+ bGPDbrush *brush = p->brush;
+ 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 */
@@ -569,7 +728,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* copy appropriate settings for stroke */
gps->totpoints = totelem;
- gps->thickness = p->gpl->thickness;
+ gps->thickness = brush->thickness;
gps->flag = gpd->sbuffer_sflag;
gps->inittime = p->inittime;
@@ -577,7 +736,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
gps->flag |= GP_STROKE_RECALC_CACHES;
/* allocate enough memory for a continuous array for storage points */
- int sublevel = gpl->sublevel;
+ int sublevel = brush->sublevel;
int new_totpoints = gps->totpoints;
for (i = 0; i < sublevel; i++) {
@@ -600,9 +759,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
-
+ /* 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;
pt++;
@@ -614,9 +778,15 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
-
+ /* 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;
}
}
@@ -626,9 +796,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
-
+ /* 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;
}
else {
@@ -703,6 +878,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* copy pressure and time */
pt->pressure = ptc->pressure;
+ pt->strength = ptc->strength;
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
}
@@ -716,28 +893,49 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
gp_subdivide_stroke(gps, totpoints);
}
}
-
+ /* apply randomness to stroke */
+ if (brush->draw_random_sub > 0.0f) {
+ gp_randomize_stroke(gps, brush);
+ }
+
/* smooth stroke after subdiv - only if there's something to do
* for each iteration, the factor is reduced to get a better smoothing without changing too much
* the original stroke
*/
- if (gpl->draw_smoothfac > 0.0f) {
+ if (brush->draw_smoothfac > 0.0f) {
float reduce = 0.0f;
- for (int r = 0; r < gpl->draw_smoothlvl; ++r) {
+ for (int r = 0; r < brush->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, gpl->draw_smoothfac - reduce, false);
+ gp_smooth_stroke(gps, i, brush->draw_smoothfac - reduce, false);
}
reduce += 0.25f; // reduce the factor
}
}
-
+ /* if parented change position relative to parent object */
+ if (gpl->parent != NULL) {
+ gp_apply_parent(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;
+ strcpy(gps->colorname, palcolor->info);
- /* add stroke to frame */
- BLI_addtail(&p->gpf->strokes, gps);
+ /* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke is added on listbase head
+ * because the drawing order is inverse and the head stroke is the first to draw. This is very useful for artist
+ * when drawing the background
+ */
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode != GP_PAINTMODE_DRAW_POLY)) {
+ BLI_addhead(&p->gpf->strokes, gps);
+ }
+ else {
+ BLI_addtail(&p->gpf->strokes, gps);
+ }
gp_stroke_added_enable(p);
}
@@ -761,12 +959,21 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, cons
(p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH))
{
RegionView3D *rv3d = p->ar->regiondata;
+ bGPDlayer *gpl = p->gpl;
+
const int mval[2] = {x, y};
float mval_3d[3];
-
+ float fpt[3];
+
+ float diff_mat[4][4];
+ /* calculate difference matrix if parent object */
+ ED_gpencil_parent_location(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);
- const float depth_pt = view3d_point_depth(rv3d, &pt->x);
+
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ const float depth_pt = view3d_point_depth(rv3d, fpt);
if (depth_pt > depth_mval) {
return true;
@@ -804,7 +1011,13 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
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);
+ }
+
if (gps->totpoints == 0) {
/* just free stroke */
if (gps->points)
@@ -816,8 +1029,14 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
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]);
-
+ 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]);
+ }
/* 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 */
@@ -826,7 +1045,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
// XXX: pressure sensitive eraser should apply here too?
MEM_freeN(gps->points);
if (gps->triangles)
- MEM_freeN(gps->triangles);
+ MEM_freeN(gps->triangles);
BLI_freelinkN(&gpf->strokes, gps);
}
}
@@ -836,7 +1055,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* Pressure threshold at which stroke should be culled: Calculated as pressure value
* below which we would have invisible strokes
*/
- const float cull_thresh = (gpl->thickness) ? 1.0f / ((float)gpl->thickness) : 1.0f;
+ const float cull_thresh = (gps->thickness) ? 1.0f / ((float)gps->thickness) : 1.0f;
/* Amount to decrease the pressure of each point with each stroke */
// TODO: Fetch from toolsettings, or compute based on thickness instead?
@@ -865,15 +1084,24 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* 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;
- /* get coordinates of point in screenspace */
- gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
- gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
-
+ 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]);
+
+ 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])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1])))
@@ -955,7 +1183,10 @@ static void gp_stroke_doeraser(tGPsdata *p)
/* loop over strokes, checking segments for intersections */
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) {
+ continue;
+ }
/* Not all strokes in the datablock may be valid in the current editor/context
* (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
*/
@@ -994,6 +1225,78 @@ static void gp_session_validatebuffer(tGPsdata *p)
p->inittime = 0.0;
}
+/* create a new palette color */
+static bGPDpalettecolor *gp_create_new_color(bGPDpalette *palette)
+{
+ bGPDpalettecolor *palcolor;
+
+ palcolor = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
+
+ return palcolor;
+}
+
+/* initialize a drawing brush */
+static void gp_init_drawing_brush(ToolSettings *ts, tGPsdata *p)
+{
+ bGPDbrush *brush;
+
+ /* if not exist, create a new one */
+ if (BLI_listbase_is_empty(&ts->gp_brushes)) {
+ /* create new brushes */
+ BKE_gpencil_brush_init_presets(ts);
+ brush = BKE_gpencil_brush_getactive(ts);
+ }
+ else {
+ /* Use the current */
+ brush = BKE_gpencil_brush_getactive(ts);
+ }
+ /* be sure curves are initializated */
+ curvemapping_initialize(brush->cur_sensitivity);
+ curvemapping_initialize(brush->cur_strength);
+ curvemapping_initialize(brush->cur_jitter);
+
+ /* asign to temp tGPsdata */
+ p->brush = brush;
+}
+
+
+/* initialize a paint palette brush and a default color if not exist */
+static void gp_init_palette(tGPsdata *p)
+{
+ bGPdata *gpd;
+ bGPDpalette *palette;
+ bGPDpalettecolor *palcolor;
+
+ gpd = p->gpd;
+
+ /* 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);
+ }
+ 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;
+ }
+ }
+
+ /* asign to temp tGPsdata */
+ p->palettecolor = palcolor;
+}
+
/* (re)init new painting data */
static bool gp_session_initdata(bContext *C, tGPsdata *p)
{
@@ -1145,7 +1448,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
else {
/* if no existing GPencil block exists, add one */
if (*gpd_ptr == NULL)
- *gpd_ptr = gpencil_data_addnew("GPencil");
+ *gpd_ptr = BKE_gpencil_data_addnew("GPencil");
p->gpd = *gpd_ptr;
}
@@ -1158,7 +1461,16 @@ 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);
+ pdata->sflag = palcolor->flag;
+
return 1;
}
@@ -1177,7 +1489,7 @@ static tGPsdata *gp_session_initpaint(bContext *C)
* erase size won't get lost
*/
p->radius = U.gp_eraser;
-
+
/* return context data for running paint operator */
return p;
}
@@ -1211,9 +1523,9 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
ToolSettings *ts = scene->toolsettings;
/* get active layer (or add a new one if non-existent) */
- p->gpl = gpencil_layer_getactive(p->gpd);
+ p->gpl = BKE_gpencil_layer_getactive(p->gpd);
if (p->gpl == NULL) {
- p->gpl = gpencil_layer_addnew(p->gpd, "GP_Layer", true);
+ p->gpl = BKE_gpencil_layer_addnew(p->gpd, "GP_Layer", true);
if (p->custom_color[3])
copy_v3_v3(p->gpl->color, p->custom_color);
@@ -1241,7 +1553,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* Add a new frame if needed (and based off the active frame,
* as we need some existing strokes to erase)
*/
- gpl->actframe = gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
/* XXX: we omit GP_FRAME_PAINT here for now,
* as it is only really useful for doing
@@ -1277,7 +1589,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
else
add_frame_mode = GP_GETFRAME_ADD_NEW;
- p->gpf = gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
+ p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
if (p->gpf == NULL) {
p->status = GP_STATUS_ERROR;
@@ -1495,7 +1807,6 @@ static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
/* ------------------------------- */
-
static void gpencil_draw_exit(bContext *C, wmOperator *op)
{
tGPsdata *p = op->customdata;
@@ -1513,7 +1824,7 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
/* 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.
@@ -1600,7 +1911,7 @@ static void gpencil_draw_status_indicators(tGPsdata *p)
break;
case GP_PAINTMODE_DRAW:
ED_area_headerprint(p->sa, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw | "
- "ESC/Enter to end (or click outside this area)"));
+ "E/ESC/Enter to end (or click outside this area)"));
break;
case GP_PAINTMODE_DRAW_POLY:
ED_area_headerprint(p->sa, IFACE_("Grease Pencil Poly Session: LMB click to place next stroke vertex | "
@@ -1691,6 +2002,31 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
*/
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) */
@@ -1725,7 +2061,9 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
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...
*/
@@ -1733,6 +2071,18 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
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);
@@ -1855,21 +2205,21 @@ 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);
}
-
/* 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);
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
else {
/* toolbar invoked - don't start drawing yet... */
@@ -1937,6 +2287,28 @@ static void gpencil_stroke_end(wmOperator *op)
p->gpf = NULL;
}
+/* Move last stroke in the listbase to the head to be drawn below all previous strokes in the layer */
+static void gpencil_move_last_stroke_to_back(bContext *C)
+{
+ /* move last stroke (the polygon) to head of the listbase stroke to draw on back of all previous strokes */
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl, gpl->actframe)) {
+ return;
+ }
+
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps = gpf->strokes.last;
+ if (ELEM(NULL, gps)) {
+ return;
+ }
+
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
+}
+
/* events handling during interactive drawing part of operator */
static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -1976,6 +2348,10 @@ 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, DKEY)) && (event->val == KM_RELEASE)) {
+ /* enable continuous if release D key in mid drawing */
+ p->scene->toolsettings->gpencil_flags |= GP_TOOL_FLAG_PAINTSESSIONS_ON;
+ }
else {
estate = OPERATOR_RUNNING_MODAL;
}
@@ -1986,9 +2362,15 @@ 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)) {
+ 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"); */
+ /* if drawing polygon and enable on back, must move stroke */
+ if ((p->scene->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
+ }
p->status = GP_STATUS_DONE;
estate = OPERATOR_FINISHED;
}
@@ -2045,6 +2427,12 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
else {
/* printf("\t\tGP - end of stroke + op\n"); */
+ /* if drawing polygon and enable on back, must move stroke */
+ if ((p->scene->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
+ }
p->status = GP_STATUS_DONE;
estate = OPERATOR_FINISHED;
}
@@ -2125,6 +2513,12 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* NOTE: Don't eter this case if an error occurred while finding the
* region (as above)
*/
+ /* if drawing polygon and enable on back, must move stroke */
+ if ((p->scene->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
+ }
p->status = GP_STATUS_DONE;
estate = OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index b6482786b4f..4cb966c6378 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_screen_types.h"
+#include "DNA_object_types.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
@@ -265,7 +266,7 @@ static void gp_select_same_layer(bContext *C)
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
bGPDstroke *gps;
bool found = false;
@@ -616,9 +617,10 @@ void GPENCIL_OT_select_less(wmOperatorType *ot)
/* NOTE: Code here is adapted (i.e. copied directly) from gpencil_paint.c::gp_stroke_eraser_dostroke()
* It would be great to de-duplicate the logic here sometime, but that can wait...
*/
-static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc,
- const int mx, const int my, const int radius,
- const bool select, rcti *rect)
+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])
{
bGPDspoint *pt1, *pt2;
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
@@ -626,7 +628,14 @@ static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc,
bool changed = false;
if (gps->totpoints == 1) {
- gp_point_to_xy(gsc, gps, gps->points, &x0, &y0);
+ 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);
+ }
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
@@ -654,9 +663,18 @@ static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc,
/* get points to work with */
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
-
- gp_point_to_xy(gsc, gps, pt1, &x0, &y0);
- gp_point_to_xy(gsc, gps, pt2, &x1, &y1);
+ 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);
+
+ 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)) ||
@@ -691,7 +709,7 @@ static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc,
}
/* Ensure that stroke selection is in sync with its points */
- gpencil_stroke_sync_selection(gps);
+ BKE_gpencil_stroke_sync_selection(gps);
}
return changed;
@@ -733,12 +751,14 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
/* find visible strokes, and select if hit */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
- changed |= gp_stroke_do_circle_sel(gps, &gsc, mx, my, radius, select, &rect);
+ changed |= gp_stroke_do_circle_sel(
+ gps, &gsc, mx, my, radius, select, &rect,
+ (gpl->parent != NULL), diff_mat);
}
- CTX_DATA_END;
-
+ GP_EDITABLE_STROKES_END;
+
/* updates */
if (changed) {
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
@@ -818,17 +838,25 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op)
WM_operator_properties_border_to_rcti(op, &rect);
/* select/deselect points */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
+
bGPDspoint *pt;
int i;
-
+
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int x0, y0;
-
+
/* convert point coords to screenspace */
- gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
-
+ 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);
+ }
+
/* test if in selection rect */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0)) {
if (select) {
@@ -837,16 +865,16 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op)
else {
pt->flag &= ~GP_SPOINT_SELECT;
}
-
+
changed = true;
}
}
-
+
/* Ensure that stroke selection is in sync with its points */
- gpencil_stroke_sync_selection(gps);
+ BKE_gpencil_stroke_sync_selection(gps);
}
- CTX_DATA_END;
-
+ GP_EDITABLE_STROKES_END;
+
/* updates */
if (changed) {
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
@@ -920,20 +948,26 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
}
/* select/deselect points */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
bGPDspoint *pt;
int i;
-
+
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int x0, y0;
-
+
/* convert point coords to screenspace */
- gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
-
+ 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);
+ }
/* 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))
+ BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX))
{
if (select) {
pt->flag |= GP_SPOINT_SELECT;
@@ -941,16 +975,16 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
else {
pt->flag &= ~GP_SPOINT_SELECT;
}
-
+
changed = true;
}
}
-
+
/* Ensure that stroke selection is in sync with its points */
- gpencil_stroke_sync_selection(gps);
+ BKE_gpencil_stroke_sync_selection(gps);
}
- CTX_DATA_END;
-
+ GP_EDITABLE_STROKES_END;
+
/* cleanup */
MEM_freeN((void *)mcords);
@@ -1020,35 +1054,42 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* First Pass: Find stroke point which gets hit */
/* XXX: maybe we should go from the top of the stack down instead... */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
bGPDspoint *pt;
int i;
-
+
/* firstly, check for hit-point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int xy[2];
-
- gp_point_to_xy(&gsc, gps, pt, &xy[0], &xy[1]);
-
+
+ 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]);
+ }
+
/* do boundbox check first */
if (!ELEM(V2D_IS_CLIPPED, xy[0], xy[1])) {
const int pt_distance = len_manhattan_v2v2_int(mval, xy);
-
+
/* check if point is inside */
if (pt_distance <= radius_squared) {
/* only use this point if it is a better match than the current hit - T44685 */
if (pt_distance < hit_distance) {
hit_stroke = gps;
- hit_point = pt;
+ hit_point = pt;
hit_distance = pt_distance;
}
}
}
}
}
- CTX_DATA_END;
-
+ GP_EDITABLE_STROKES_END;
+
/* Abort if nothing hit... */
if (ELEM(NULL, hit_stroke, hit_point)) {
return OPERATOR_CANCELLED;
@@ -1111,7 +1152,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
hit_point->flag &= ~GP_SPOINT_SELECT;
/* ensure that stroke is selected correctly */
- gpencil_stroke_sync_selection(hit_stroke);
+ BKE_gpencil_stroke_sync_selection(hit_stroke);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index f9b479ca03d..793ed2a07d0 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -100,14 +100,14 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name)
bGPdata *gpd = *gpd_ptr;
bGPDlayer *gpl, *gpld;
- free_gpencil_layers(&gpd->layers);
+ BKE_gpencil_free_layers(&gpd->layers);
/* copy layers */
BLI_listbase_clear(&gpd->layers);
for (gpl = new_gpd->layers.first; gpl; gpl = gpl->next) {
/* make a copy of source layer and its data */
- gpld = gpencil_layer_duplicate(gpl);
+ gpld = BKE_gpencil_layer_duplicate(gpl);
BLI_addtail(&gpd->layers, gpld);
}
}
@@ -142,7 +142,7 @@ void gpencil_undo_push(bGPdata *gpd)
*/
undo_node->gpd->adt = NULL;
- BKE_gpencil_free(undo_node->gpd);
+ BKE_gpencil_free(undo_node->gpd, false);
MEM_freeN(undo_node->gpd);
BLI_freelinkN(&undo_nodes, undo_node);
@@ -153,7 +153,7 @@ void gpencil_undo_push(bGPdata *gpd)
/* create new undo node */
undo_node = MEM_callocN(sizeof(bGPundonode), "gpencil undo node");
- undo_node->gpd = gpencil_data_duplicate(G.main, gpd, true);
+ undo_node->gpd = BKE_gpencil_data_duplicate(G.main, gpd, true);
cur_node = undo_node;
@@ -170,7 +170,7 @@ void gpencil_undo_finish(void)
*/
undo_node->gpd->adt = NULL;
- BKE_gpencil_free(undo_node->gpd);
+ BKE_gpencil_free(undo_node->gpd, false);
MEM_freeN(undo_node->gpd);
undo_node = undo_node->next;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index d62625baaa4..ed9a591dcbe 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -17,7 +17,7 @@
*
* The Original Code is Copyright (C) 2014, Blender Foundation
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -32,9 +32,13 @@
#include <stddef.h>
#include <math.h>
+#include "MEM_guardedalloc.h"
+
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+#include "BLI_rand.h"
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
@@ -46,6 +50,7 @@
#include "BKE_context.h"
#include "BKE_gpencil.h"
#include "BKE_tracking.h"
+#include "BKE_action.h"
#include "WM_api.h"
@@ -220,7 +225,7 @@ bool ED_gpencil_has_keyframe_v3d(Scene *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 = gpencil_layer_getactive(scene->gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(scene->gpd);
if (gpl) {
if (gpl->actframe) {
// XXX: assumes that frame has been fetched already
@@ -234,7 +239,7 @@ bool ED_gpencil_has_keyframe_v3d(Scene *scene, Object *ob, int cfra)
}
if (ob && ob->gpd) {
- bGPDlayer *gpl = gpencil_layer_getactive(ob->gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->gpd);
if (gpl) {
if (gpl->actframe) {
// XXX: assumes that frame has been fetched already
@@ -264,11 +269,39 @@ int gp_add_poll(bContext *C)
int gp_active_layer_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
return (gpl != NULL);
}
+/* poll callback for checking if there is an active brush */
+int 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 */
+int 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 */
+int 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);
+}
+
/* ******************************************************** */
/* Dynamic Enums of GP Layers */
/* NOTE: These include an option to create a new layer and use that... */
@@ -412,6 +445,60 @@ bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
return ED_gpencil_stroke_can_use_direct(sa, gps);
}
+/* Check whether given stroke can be edited for the current color */
+bool ED_gpencil_stroke_color_use(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)
+ return false;
+ if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_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 */
@@ -451,6 +538,50 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
}
}
+/* convert point to parent space */
+void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt)
+{
+ float fpt[3];
+
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ copy_v3_v3(&r_pt->x, fpt);
+}
+
+/* Change position relative to parent object */
+void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps)
+{
+ bGPDspoint *pt;
+ int i;
+
+ /* undo matrix */
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+ float fpt[3];
+
+ ED_gpencil_parent_location(gpl, diff_mat);
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+
+ for (i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
+ copy_v3_v3(&pt->x, fpt);
+ }
+}
+
+/* Change point position relative to parent object */
+void gp_apply_parent_point(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);
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+
+ mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
+ copy_v3_v3(&pt->x, fpt);
+}
/* Convert Grease Pencil points to screen-space values
* WARNING: This assumes that the caller has already checked whether the stroke in question can be drawn
@@ -591,25 +722,107 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure)
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;
}
+#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;
}
+#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)
+{
+ bGPDspoint *ptb = &gps->points[i];
+
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
+
+ /* 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 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 - inf) * ptb->strength + inf * optimal;
+
+ return true;
+}
+
+/**
+* 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)
+{
+ bGPDspoint *ptb = &gps->points[i];
+
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
+
+ /* 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;
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->pressure = (1.0f - inf) * ptb->pressure + inf * optimal;
+
+ return true;
+}
+
+/**
* 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)
@@ -633,16 +846,99 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints)
interp_v3_v3v3(&pt->x, &prev->x, &next->x, 0.5f);
pt->pressure = interpf(prev->pressure, next->pressure, 0.5f);
- pt->time = interpf(prev->time, next->time, 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);
}
/* Update to new total number of points */
gps->totpoints = new_totpoints;
}
-/* ******************************************************** */
+/**
+ * Add randomness to stroke
+ * \param gps Stroke data
+ * \param brsuh Brush data
+ */
+void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush)
+{
+ bGPDspoint *pt1, *pt2, *pt3;
+ float v1[3];
+ float v2[3];
+ if (gps->totpoints < 3) {
+ return;
+ }
+
+ /* get two vectors using 3 points */
+ pt1 = &gps->points[0];
+ pt2 = &gps->points[1];
+ pt3 = &gps->points[(int)(gps->totpoints * 0.75)];
+
+ sub_v3_v3v3(v1, &pt2->x, &pt1->x);
+ sub_v3_v3v3(v2, &pt3->x, &pt2->x);
+ normalize_v3(v1);
+ normalize_v3(v2);
+
+ /* get normal vector to plane created by two vectors */
+ float normal[3];
+ cross_v3_v3v3(normal, v1, v2);
+ normalize_v3(normal);
+ /* get orthogonal vector to plane to rotate random effect */
+ float ortho[3];
+ cross_v3_v3v3(ortho, v1, normal);
+ normalize_v3(ortho);
+ /* Read all points and apply shift vector (first and last point not modified) */
+ for (int i = 1; i < gps->totpoints - 1; ++i) {
+ bGPDspoint *pt = &gps->points[i];
+ /* get vector with shift (apply a division because random is too sensitive */
+ const float fac = BLI_frand() * (brush->draw_random_sub / 10.0f);
+ float svec[3];
+ copy_v3_v3(svec, ortho);
+ if (BLI_frand() > 0.5f) {
+ mul_v3_fl(svec, -fac);
+ }
+ else {
+ mul_v3_fl(svec, fac);
+ }
+
+ /* apply shift */
+ add_v3_v3(&pt->x, svec);
+ }
+
+}
+/* calculate difference matrix */
+void ED_gpencil_parent_location(bGPDlayer *gpl, float diff_mat[4][4])
+{
+ Object *ob = gpl->parent;
+ if (ob == NULL) {
+ unit_m4(diff_mat);
+ return;
+ }
+ else {
+ if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) {
+ mul_m4_m4m4(diff_mat, ob->obmat, gpl->inverse);
+ return;
+ }
+ else if (gpl->partype == PARBONE) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, gpl->parsubstr);
+ if (pchan) {
+ float tmp_mat[4][4];
+ mul_m4_m4m4(tmp_mat, ob->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) */
+ }
+ return;
+ }
+ else {
+ unit_m4(diff_mat); /* not defined type */
+ }
+ }
+}
+/* ******************************************************** */
bool ED_gpencil_stroke_minmax(
const bGPDstroke *gps, const bool use_select,
float r_min[3], float r_max[3])
@@ -659,3 +955,74 @@ bool ED_gpencil_stroke_minmax(
}
return changed;
}
+/* Dynamic Enums of GP Brushes */
+
+EnumPropertyItem *ED_gpencil_brushes_enum_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPDbrush *brush;
+ EnumPropertyItem *item = NULL, item_tmp = { 0 };
+ int totitem = 0;
+ int i = 0;
+
+ if (ELEM(NULL, C, ts)) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ /* 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;
+
+ if (brush->flag & GP_BRUSH_ACTIVE)
+ item_tmp.icon = ICON_BRUSH_DATA;
+ else
+ item_tmp.icon = ICON_NONE;
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+/* Dynamic Enums of GP Palettes */
+
+EnumPropertyItem *ED_gpencil_palettes_enum_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDpalette *palette;
+ EnumPropertyItem *item = NULL, item_tmp = { 0 };
+ int totitem = 0;
+ int i = 0;
+
+ if (ELEM(NULL, C, gpd)) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ /* 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;
+
+ if (palette->flag & PL_PALETTE_ACTIVE)
+ item_tmp.icon = ICON_COLOR;
+ else
+ item_tmp.icon = ICON_NONE;
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+/* ******************************************************** */
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 0940f594482..bfd89e90fce 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -156,6 +156,7 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_DSMAT,
ANIMTYPE_DSLAM,
ANIMTYPE_DSCAM,
+ ANIMTYPE_DSCACHEFILE,
ANIMTYPE_DSCUR,
ANIMTYPE_DSSKEY,
ANIMTYPE_DSWOR,
@@ -275,6 +276,7 @@ typedef enum eAnimFilter_Flags {
#define FILTER_MAT_OBJD(ma) (CHECK_TYPE_INLINE(ma, Material *), ((ma->flag & MA_DS_EXPAND)))
#define FILTER_LAM_OBJD(la) (CHECK_TYPE_INLINE(la, Lamp *), ((la->flag & LA_DS_EXPAND)))
#define FILTER_CAM_OBJD(ca) (CHECK_TYPE_INLINE(ca, Camera *), ((ca->flag & CAM_DS_EXPAND)))
+#define FILTER_CACHEFILE_OBJD(cf) (CHECK_TYPE_INLINE(cf, CacheFile *), ((cf->flag & CACHEFILE_DS_EXPAND)))
#define FILTER_CUR_OBJD(cu) (CHECK_TYPE_INLINE(cu, Curve *), ((cu->flag & CU_DS_EXPAND)))
#define FILTER_PART_OBJD(part) (CHECK_TYPE_INLINE(part, ParticleSettings *), ((part->flag & PART_DS_EXPAND)))
#define FILTER_MBALL_OBJD(mb) (CHECK_TYPE_INLINE(mb, MetaBall *), ((mb->flag2 & MB_DS_EXPAND)))
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index de5ab80a88f..d526b0841cc 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -41,6 +41,8 @@ struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
+struct bGPDpalette;
+struct bGPDpalettecolor;
struct bAnimContext;
struct KeyframeEditData;
struct PointerRNA;
@@ -57,6 +59,7 @@ struct wmKeyConfig;
typedef struct tGPspoint {
int x, y; /* x and y coordinates of cursor (in relative to area) */
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) */
} tGPspoint;
@@ -86,6 +89,9 @@ 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,
@@ -142,4 +148,10 @@ bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mod
int ED_gpencil_session_active(void);
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]);
+
+
#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 b1f3f012e09..c478a8b17e5 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -34,6 +34,7 @@
struct bAnimContext;
struct AnimData;
+struct CacheFile;
struct FCurve;
struct bDopeSheet;
struct bAction;
@@ -141,6 +142,8 @@ void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct D
void action_to_keylist(struct AnimData *adt, struct bAction *act, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
/* Object */
void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
+/* Cache File */
+void cachefile_to_keylist(struct bDopeSheet *ads, struct CacheFile *cache_file, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
/* Scene */
void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
/* DopeSheet Summary */
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index d85b60dcc43..e016e014a1a 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -320,9 +320,9 @@ DEF_ICON(OUTLINER_OB_SPEAKER)
DEF_ICON(BLANK123)
DEF_ICON(BLANK124)
DEF_ICON(BLANK125)
- DEF_ICON(BLANK126)
- DEF_ICON(BLANK127)
#endif
+DEF_ICON(RESTRICT_COLOR_OFF)
+DEF_ICON(RESTRICT_COLOR_ON)
DEF_ICON(RESTRICT_VIEW_OFF)
DEF_ICON(RESTRICT_VIEW_ON)
DEF_ICON(RESTRICT_SELECT_OFF)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index a623f5cfb9c..1f053c806b0 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -382,7 +382,11 @@ typedef bool (*uiMenuStepFunc)(struct bContext *C, int direction, void *arg1);
typedef struct uiPopupMenu uiPopupMenu;
-struct uiPopupMenu *UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL();
+uiPopupMenu *UI_popup_menu_begin(
+ struct bContext *C, const char *title, int icon) ATTR_NONNULL();
+uiPopupMenu *UI_popup_menu_begin_ex(
+ struct bContext *C, const char *title, const char *block_name,
+ int icon) ATTR_NONNULL();
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *head);
struct uiLayout *UI_popup_menu_layout(uiPopupMenu *head);
@@ -941,6 +945,7 @@ void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
void uiTemplateComponentMenu(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name);
void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color);
+void uiTemplateCacheFile(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname);
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 11703208b2a..79831cefde6 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -10156,6 +10156,10 @@ static void ui_popup_handler_remove(bContext *C, void *userdata)
{
uiPopupBlockHandle *menu = userdata;
+ if (menu->cancel_func) {
+ menu->cancel_func(C, menu->popup_arg);
+ }
+
/* free menu block if window is closed for some reason */
ui_popup_block_free(C, menu);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 4107414a240..22a450d2523 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1541,6 +1541,8 @@ int UI_idcode_icon_get(const int idcode)
return ICON_BRUSH_DATA;
case ID_CA:
return ICON_CAMERA_DATA;
+ case ID_CF:
+ return ICON_FILE;
case ID_CU:
return ICON_CURVE_DATA;
case ID_GD:
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index f02aad1ff87..8336efa381b 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -548,6 +548,8 @@ struct uiPopupBlockHandle {
/* store data for refreshing popups */
struct uiPopupBlockCreate popup_create_vars;
+ /* true if we can re-create the popup using 'popup_create_vars' */
+ bool can_refresh;
struct wmTimer *scrolltimer;
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 2caf52cf8dc..c621fcf493d 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -1701,7 +1701,9 @@ static void ui_block_region_draw(const bContext *C, ARegion *ar)
ar->do_draw &= ~RGN_DRAW_REFRESH_UI;
for (block = ar->uiblocks.first; block; block = block_next) {
block_next = block->next;
- ui_popup_block_refresh((bContext *)C, block->handle, NULL, NULL);
+ if (block->handle->can_refresh) {
+ ui_popup_block_refresh((bContext *)C, block->handle, NULL, NULL);
+ }
}
}
@@ -1811,6 +1813,8 @@ uiBlock *ui_popup_block_refresh(
bContext *C, uiPopupBlockHandle *handle,
ARegion *butregion, uiBut *but)
{
+ BLI_assert(handle->can_refresh == true);
+
const int margin = UI_POPUP_MARGIN;
wmWindow *window = CTX_wm_window(C);
ARegion *ar = handle->region;
@@ -2001,6 +2005,8 @@ uiPopupBlockHandle *ui_popup_block_create(
handle->popup_create_vars.arg = arg;
handle->popup_create_vars.butregion = but ? butregion : NULL;
copy_v2_v2_int(handle->popup_create_vars.event_xy, &window->eventstate->x);
+ /* caller may free vars used to create this popup, in that case this variable should be disabled. */
+ handle->can_refresh = true;
/* create area region */
ar = ui_region_temp_add(CTX_wm_screen(C));
@@ -2800,6 +2806,7 @@ uiPopupBlockHandle *ui_popup_menu_create(
WM_event_add_mousemove(C);
}
+ handle->can_refresh = false;
MEM_freeN(pup);
return handle;
@@ -2807,14 +2814,17 @@ uiPopupBlockHandle *ui_popup_menu_create(
/******************** Popup Menu API with begin and end ***********************/
-/* only return handler, and set optional title */
-uiPopupMenu *UI_popup_menu_begin(bContext *C, const char *title, int icon)
+/**
+ * Only return handler, and set optional title.
+ * \param block_name: Assigned to uiBlock.name (useful info for debugging).
+ */
+uiPopupMenu *UI_popup_menu_begin_ex(bContext *C, const char *title, const char *block_name, int icon)
{
uiStyle *style = UI_style_get_dpi();
uiPopupMenu *pup = MEM_callocN(sizeof(uiPopupMenu), "popup menu");
uiBut *but;
- pup->block = UI_block_begin(C, NULL, __func__, UI_EMBOSS_PULLDOWN);
+ pup->block = UI_block_begin(C, NULL, block_name, UI_EMBOSS_PULLDOWN);
pup->block->flag |= UI_BLOCK_POPUP_MEMORY | UI_BLOCK_IS_FLIP;
pup->block->puphash = ui_popup_menu_hash(title);
pup->layout = UI_block_layout(pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, MENU_PADDING, style);
@@ -2845,6 +2855,11 @@ uiPopupMenu *UI_popup_menu_begin(bContext *C, const char *title, int icon)
return pup;
}
+uiPopupMenu *UI_popup_menu_begin(bContext *C, const char *title, int icon)
+{
+ return UI_popup_menu_begin_ex(C, title, __func__, icon);
+}
+
/* set the whole structure to work */
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
{
@@ -2860,7 +2875,8 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
UI_popup_handlers_add(C, &window->modalhandlers, menu, 0);
WM_event_add_mousemove(C);
-
+
+ menu->can_refresh = false;
MEM_freeN(pup);
}
@@ -2991,6 +3007,7 @@ void UI_pie_menu_end(bContext *C, uiPieMenu *pie)
menu, WM_HANDLER_ACCEPT_DBL_CLICK);
WM_event_add_mousemove(C);
+ menu->can_refresh = false;
MEM_freeN(pie);
}
@@ -3203,7 +3220,8 @@ void UI_popup_menu_reports(bContext *C, ReportList *reports)
if (pup == NULL) {
char title[UI_MAX_DRAW_STR];
BLI_snprintf(title, sizeof(title), "%s: %s", IFACE_("Report"), report->typestr);
- pup = UI_popup_menu_begin(C, title, ICON_NONE);
+ /* popup_menu stuff does just what we need (but pass meaningful block name) */
+ pup = UI_popup_menu_begin_ex(C, title, __func__, ICON_NONE);
layout = UI_popup_menu_layout(pup);
}
else {
@@ -3332,7 +3350,7 @@ void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block)
UI_popup_handlers_remove(&win->modalhandlers, block->handle);
ui_popup_block_free(C, block->handle);
- /* In the case we have nested popups, closing one may need to redraw anorher, see: T48874 */
+ /* In the case we have nested popups, closing one may need to redraw another, see: T48874 */
for (ARegion *ar = win->screen->regionbase.first; ar; ar = ar->next) {
ED_region_tag_refresh_ui(ar);
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index aec4065adaf..241da5decc6 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -32,6 +32,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_cachefile_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -368,6 +369,7 @@ static const char *template_id_browse_tip(StructRNA *type)
case ID_MSK: return N_("Browse Mask to be linked");
case ID_PAL: return N_("Browse Palette Data to be linked");
case ID_PC: return N_("Browse Paint Curve Data to be linked");
+ case ID_CF: return N_("Browse Cache Files to be linked");
}
}
return N_("Browse ID data to be linked");
@@ -872,8 +874,8 @@ static uiLayout *draw_modifier(
/* mode enabling buttons */
UI_block_align_begin(block);
- /* Softbody not allowed in this situation, enforce! */
- if (((md->type != eModifierType_Softbody && md->type != eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) &&
+ /* Collision and Surface are always enabled, hide buttons! */
+ if (((md->type != eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) &&
(md->type != eModifierType_Surface) )
{
uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE);
@@ -1940,6 +1942,7 @@ enum {
UICURVE_FUNC_RESET_VIEW,
UICURVE_FUNC_HANDLE_VECTOR,
UICURVE_FUNC_HANDLE_AUTO,
+ UICURVE_FUNC_HANDLE_AUTO_ANIM,
UICURVE_FUNC_EXTEND_HOZ,
UICURVE_FUNC_EXTEND_EXP,
};
@@ -1960,13 +1963,16 @@ static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
cumap->curr = cumap->clipr;
break;
case UICURVE_FUNC_HANDLE_VECTOR: /* set vector */
- curvemap_sethandle(cuma, 1);
+ curvemap_handle_set(cuma, HD_VECT);
curvemapping_changed(cumap, false);
break;
case UICURVE_FUNC_HANDLE_AUTO: /* set auto */
- curvemap_sethandle(cuma, 0);
+ curvemap_handle_set(cuma, HD_AUTO);
curvemapping_changed(cumap, false);
break;
+ case UICURVE_FUNC_HANDLE_AUTO_ANIM: /* set auto-clamped */
+ curvemap_handle_set(cuma, HD_AUTO_ANIM);
+ curvemapping_changed(cumap, false);
case UICURVE_FUNC_EXTEND_HOZ: /* extend horiz */
cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
curvemapping_changed(cumap, false);
@@ -2000,6 +2006,9 @@ static uiBlock *curvemap_tools_func(
uiDefIconTextBut(
block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Auto Handle"),
0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO, "");
+ uiDefIconTextBut(
+ block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Auto Clamped Handle"),
+ 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO_ANIM, "");
}
if (show_extend) {
@@ -3841,3 +3850,73 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color)
UI_block_align_end(block);
}
+
+/********************************* Cache File *********************************/
+
+void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname)
+{
+ if (!ptr->data) {
+ return;
+ }
+
+ PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+
+ if (!prop) {
+ printf("%s: property not found: %s.%s\n",
+ __func__, RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ if (RNA_property_type(prop) != PROP_POINTER) {
+ printf("%s: expected pointer property for %s.%s\n",
+ __func__, RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ PointerRNA fileptr = RNA_property_pointer_get(ptr, prop);
+ CacheFile *file = fileptr.data;
+
+ uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr);
+
+ uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL);
+
+ if (!file) {
+ return;
+ }
+
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiBlock *block = uiLayoutGetBlock(row);
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("File Path:"), 0, 19, 145, 19, NULL, 0, 0, 0, 0, "");
+
+ row = uiLayoutRow(layout, false);
+ uiLayout *split = uiLayoutSplit(row, 0.0f, false);
+ row = uiLayoutRow(split, true);
+
+ uiItemR(row, &fileptr, "filepath", 0, "", ICON_NONE);
+ uiItemO(row, "", ICON_FILE_REFRESH, "cachefile.reload");
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &fileptr, "is_sequence", 0, "Is Sequence", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &fileptr, "override_frame", 0, "Override Frame", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(row, RNA_boolean_get(&fileptr, "override_frame"));
+ uiItemR(row, &fileptr, "frame", 0, "Frame", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &fileptr, "scale", 0, "Scale", ICON_NONE);
+
+ /* TODO: unused for now, so no need to expose. */
+#if 0
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &fileptr, "forward_axis", 0, "Forward Axis", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &fileptr, "up_axis", 0, "Up Axis", ICON_NONE);
+#endif
+}
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 828cb494eab..b3bbce939a5 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -28,6 +28,8 @@ set(INC
../../makesrna
../../windowmanager
../../collada
+ ../../alembic
+ ../../../../intern/guardedalloc
)
set(INC_SYS
@@ -35,9 +37,13 @@ set(INC_SYS
)
set(SRC
+ io_alembic.c
+ io_cache.c
io_collada.c
io_ops.c
+ io_alembic.h
+ io_cache.h
io_collada.h
io_ops.h
)
@@ -46,6 +52,14 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
+if(WITH_ALEMBIC)
+ add_definitions(-DWITH_ALEMBIC)
+
+ if(WITH_ALEMBIC_HDF5)
+ add_definitions(-DWITH_ALEMBIC_HDF5)
+ endif()
+endif()
+
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
new file mode 100644
index 00000000000..7a7c42e501b
--- /dev/null
+++ b/source/blender/editors/io/io_alembic.c
@@ -0,0 +1,458 @@
+/*
+ * ***** 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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifdef WITH_ALEMBIC
+
+/* needed for directory lookup */
+#ifndef WIN32
+# include <dirent.h>
+#else
+# include "BLI_winstuff.h"
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "io_alembic.h"
+
+#include "ABC_alembic.h"
+
+static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ char filepath[FILE_MAX];
+ BLI_strncpy(filepath, G.main->name, sizeof(filepath));
+ BLI_replace_extension(filepath, sizeof(filepath), ".abc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+
+ UNUSED_VARS(event);
+}
+
+static int wm_alembic_export_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ char filename[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ const struct AlembicExportParams params = {
+ .frame_start = RNA_int_get(op->ptr, "start"),
+ .frame_end = RNA_int_get(op->ptr, "end"),
+
+ .frame_step_xform = 1.0 / (double)RNA_int_get(op->ptr, "xsamples"),
+ .frame_step_shape = 1.0 / (double)RNA_int_get(op->ptr, "gsamples"),
+
+ .shutter_open = RNA_float_get(op->ptr, "sh_open"),
+ .shutter_close = RNA_float_get(op->ptr, "sh_close"),
+
+ .selected_only = RNA_boolean_get(op->ptr, "selected"),
+ .uvs = RNA_boolean_get(op->ptr, "uvs"),
+ .normals = RNA_boolean_get(op->ptr, "normals"),
+ .vcolors = RNA_boolean_get(op->ptr, "vcolors"),
+ .apply_subdiv = RNA_boolean_get(op->ptr, "apply_subdiv"),
+ .flatten_hierarchy = RNA_boolean_get(op->ptr, "flatten"),
+ .visible_layers_only = RNA_boolean_get(op->ptr, "visible_layers_only"),
+ .renderable_only = RNA_boolean_get(op->ptr, "renderable_only"),
+ .face_sets = RNA_boolean_get(op->ptr, "face_sets"),
+ .use_subdiv_schema = RNA_boolean_get(op->ptr, "subdiv_schema"),
+ .compression_type = RNA_enum_get(op->ptr, "compression_type"),
+ .packuv = RNA_boolean_get(op->ptr, "packuv"),
+
+ .global_scale = RNA_float_get(op->ptr, "global_scale"),
+ };
+
+ ABC_export(CTX_data_scene(C), C, filename, &params);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
+{
+ uiLayout *box = uiLayoutBox(layout);
+ uiLayout *row;
+
+#ifdef WITH_ALEMBIC_HDF5
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Archive Options:"), ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "compression_type", 0, NULL, ICON_NONE);
+#endif
+
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "global_scale", 0, NULL, ICON_NONE);
+
+ /* Scene Options */
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Scene Options:"), ICON_SCENE_DATA);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "start", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "end", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "xsamples", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "gsamples", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "sh_open", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "sh_close", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "selected", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "renderable_only", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "visible_layers_only", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "flatten", 0, NULL, ICON_NONE);
+
+ /* Object Data */
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Object Options:"), ICON_OBJECT_DATA);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "uvs", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "packuv", 0, NULL, ICON_NONE);
+ uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "uvs"));
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "normals", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "vcolors", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "face_sets", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "subdiv_schema", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "apply_subdiv", 0, NULL, ICON_NONE);
+}
+
+static void wm_alembic_export_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ PointerRNA ptr;
+
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+ ui_alembic_export_settings(op->layout, &ptr);
+}
+
+void WM_OT_alembic_export(wmOperatorType *ot)
+{
+ ot->name = "Export Alembic Archive";
+ ot->idname = "WM_OT_alembic_export";
+
+ ot->invoke = wm_alembic_export_invoke;
+ ot->exec = wm_alembic_export_exec;
+ ot->poll = WM_operator_winactive;
+ ot->ui = wm_alembic_export_draw;
+
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
+ FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+
+ RNA_def_int(ot->srna, "start", 1, INT_MIN, INT_MAX,
+ "Start Frame", "Start Frame", INT_MIN, INT_MAX);
+
+ RNA_def_int(ot->srna, "end", 1, INT_MIN, INT_MAX,
+ "End Frame", "End Frame", INT_MIN, INT_MAX);
+
+ RNA_def_int(ot->srna, "xsamples", 1, 1, 128,
+ "Transform Samples", "Number of times per frame transformations are sampled", 1, 128);
+
+ RNA_def_int(ot->srna, "gsamples", 1, 1, 128,
+ "Geometry Samples", "Number of times per frame object datas are sampled", 1, 128);
+
+ RNA_def_float(ot->srna, "sh_open", 0.0f, -1.0f, 1.0f,
+ "Shutter Open", "Time at which the shutter is open", -1.0f, 1.0f);
+
+ RNA_def_float(ot->srna, "sh_close", 1.0f, -1.0f, 1.0f,
+ "Shutter Close", "Time at which the shutter is closed", -1.0f, 1.0f);
+
+ RNA_def_boolean(ot->srna, "selected", 0,
+ "Selected Objects Only", "Export only selected objects");
+
+ RNA_def_boolean(ot->srna, "renderable_only", 1,
+ "Renderable Objects Only",
+ "Export only objects marked renderable in the outliner");
+
+ RNA_def_boolean(ot->srna, "visible_layers_only", 0,
+ "Visible Layers Only", "Export only objects in visible layers");
+
+ RNA_def_boolean(ot->srna, "flatten", 0,
+ "Flatten Hierarchy",
+ "Do not preserve objects' parent/children relationship");
+
+ RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Export UVs");
+
+ RNA_def_boolean(ot->srna, "packuv", 1, "Pack UV Islands",
+ "Export UVs with packed island");
+
+ RNA_def_boolean(ot->srna, "normals", 1, "Normals", "Export normals");
+
+ RNA_def_boolean(ot->srna, "vcolors", 0, "Vertex colors", "Export vertex colors");
+
+ RNA_def_boolean(ot->srna, "face_sets", 0, "Face Sets", "Export per face shading group assignments");
+
+ RNA_def_boolean(ot->srna, "subdiv_schema", 0,
+ "Use Subdivision Schema",
+ "Export meshes using Alembic's subdivision schema");
+
+ RNA_def_boolean(ot->srna, "apply_subdiv", 0,
+ "Apply Subsurf", "Export subdivision surfaces as meshes");
+
+ RNA_def_enum(ot->srna, "compression_type", rna_enum_abc_compression_items,
+ ABC_ARCHIVE_OGAWA, "Compression", "");
+
+ RNA_def_float(ot->srna, "global_scale", 1.0f, 0.0001f, 1000.0f, "Scale",
+ "Value by which to enlarge or shrink the objects with respect to the world's origin",
+ 0.0001f, 1000.0f);
+}
+
+/* ************************************************************************** */
+
+/* TODO(kevin): check on de-duplicating all this with code in image_ops.c */
+
+typedef struct CacheFrame {
+ struct CacheFrame *next, *prev;
+ int framenr;
+} CacheFrame;
+
+static int cmp_frame(const void *a, const void *b)
+{
+ const CacheFrame *frame_a = a;
+ const CacheFrame *frame_b = b;
+
+ if (frame_a->framenr < frame_b->framenr) return -1;
+ if (frame_a->framenr > frame_b->framenr) return 1;
+ return 0;
+}
+
+static int get_sequence_len(char *filename, int *ofs)
+{
+ int frame;
+ int numdigit;
+
+ if (!BLI_path_frame_get(filename, &frame, &numdigit)) {
+ return 1;
+ }
+
+ char path[FILE_MAX];
+ BLI_split_dir_part(filename, path, FILE_MAX);
+
+ DIR *dir = opendir(path);
+
+ const char *ext = ".abc";
+ const char *basename = BLI_path_basename(filename);
+ const int len = strlen(basename) - (numdigit + strlen(ext));
+
+ ListBase frames;
+ BLI_listbase_clear(&frames);
+
+ struct dirent *fname;
+ while ((fname = readdir(dir)) != NULL) {
+ /* do we have the right extension? */
+ if (!strstr(fname->d_name, ext)) {
+ continue;
+ }
+
+ if (!STREQLEN(basename, fname->d_name, len)) {
+ continue;
+ }
+
+ CacheFrame *cache_frame = MEM_callocN(sizeof(CacheFrame), "abc_frame");
+
+ BLI_path_frame_get(fname->d_name, &cache_frame->framenr, &numdigit);
+
+ BLI_addtail(&frames, cache_frame);
+ }
+
+ closedir(dir);
+
+ BLI_listbase_sort(&frames, cmp_frame);
+
+ CacheFrame *cache_frame = frames.first;
+
+ if (cache_frame) {
+ int frame_curr = cache_frame->framenr;
+ (*ofs) = frame_curr;
+
+ while (cache_frame && (cache_frame->framenr == frame_curr)) {
+ ++frame_curr;
+ cache_frame = cache_frame->next;
+ }
+
+ BLI_freelistN(&frames);
+
+ return frame_curr - (*ofs);
+ }
+
+ return 1;
+}
+
+/* ************************************************************************** */
+
+static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr)
+{
+ uiLayout *box = uiLayoutBox(layout);
+ uiLayout *row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "scale", 0, NULL, ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Options:"), ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "set_frame_range", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "is_sequence", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "validate_meshes", 0, NULL, ICON_NONE);
+}
+
+static void wm_alembic_import_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ PointerRNA ptr;
+
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+ ui_alembic_import_settings(op->layout, &ptr);
+}
+
+static int wm_alembic_import_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ char filename[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ const float scale = RNA_float_get(op->ptr, "scale");
+ const bool is_sequence = RNA_boolean_get(op->ptr, "is_sequence");
+ const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range");
+ const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
+
+ int offset = 0;
+ int sequence_len = 1;
+
+ if (is_sequence) {
+ sequence_len = get_sequence_len(filename, &offset);
+ }
+
+ ABC_import(C, filename, scale, is_sequence, set_frame_range, sequence_len, offset, validate_meshes);
+
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_alembic_import(wmOperatorType *ot)
+{
+ ot->name = "Import Alembic Archive";
+ ot->idname = "WM_OT_alembic_import";
+
+ ot->invoke = WM_operator_filesel;
+ ot->exec = wm_alembic_import_exec;
+ ot->poll = WM_operator_winactive;
+ ot->ui = wm_alembic_import_draw;
+
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
+ FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+
+ RNA_def_float(ot->srna, "scale", 1.0f, 0.0001f, 1000.0f, "Scale",
+ "Value by which to enlarge or shrink the objects with respect to the world's origin",
+ 0.0001f, 1000.0f);
+
+ RNA_def_boolean(ot->srna, "set_frame_range", true,
+ "Set Frame Range",
+ "If checked, update scene's start and end frame to match those of the Alembic archive");
+
+ RNA_def_boolean(ot->srna, "validate_meshes", 0,
+ "Validate Meshes", "Check imported mesh objects for invalid data (slow)");
+
+ RNA_def_boolean(ot->srna, "is_sequence", false, "Is Sequence",
+ "Set to true if the cache is split into separate files");
+}
+
+#endif
diff --git a/source/blender/editors/io/io_alembic.h b/source/blender/editors/io/io_alembic.h
new file mode 100644
index 00000000000..5eefabef4be
--- /dev/null
+++ b/source/blender/editors/io/io_alembic.h
@@ -0,0 +1,37 @@
+/*
+ * ***** 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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef __IO_ALEMBIC_H__
+#define __IO_ALEMBIC_H__
+
+/** \file blender/editors/io/io_alembic.h
+ * \ingroup editor/io
+ */
+
+struct wmOperatorType;
+
+void WM_OT_alembic_export(struct wmOperatorType *ot);
+void WM_OT_alembic_import(struct wmOperatorType *ot);
+
+#endif /* __IO_ALEMBIC_H__ */
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
new file mode 100644
index 00000000000..d6e2c1ae204
--- /dev/null
+++ b/source/blender/editors/io/io_cache.c
@@ -0,0 +1,162 @@
+/*
+ * ***** 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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_cachefile_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "BKE_cachefile.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "io_cache.h"
+
+static void cachefile_init(bContext *C, wmOperator *op)
+{
+ PropertyPointerRNA *pprop;
+
+ op->customdata = pprop = MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
+ UI_context_active_but_prop_get_templateID(C, &pprop->ptr, &pprop->prop);
+}
+
+static int cachefile_open_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ char filepath[FILE_MAX];
+ BLI_strncpy(filepath, G.main->name, sizeof(filepath));
+ BLI_replace_extension(filepath, sizeof(filepath), ".abc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ cachefile_init(C, op);
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+
+ UNUSED_VARS(event);
+}
+
+static void open_cancel(bContext *UNUSED(C), wmOperator *op)
+{
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+}
+
+static int cachefile_open_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ char filename[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ Main *bmain = CTX_data_main(C);
+
+ CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filename));
+ BLI_strncpy(cache_file->filepath, filename, FILE_MAX);
+ BKE_cachefile_reload(bmain, cache_file);
+
+ /* hook into UI */
+ PropertyPointerRNA *pprop = op->customdata;
+
+ if (pprop->prop) {
+ /* when creating new ID blocks, use is already 1, but RNA
+ * pointer se also increases user, so this compensates it */
+ id_us_min(&cache_file->id);
+
+ PointerRNA idptr;
+ RNA_id_pointer_create(&cache_file->id, &idptr);
+ RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
+ RNA_property_update(C, &pprop->ptr, pprop->prop);
+ }
+
+ MEM_freeN(op->customdata);
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHEFILE_OT_open(wmOperatorType *ot)
+{
+ ot->name = "Open Cache File";
+ ot->idname = "CACHEFILE_OT_open";
+
+ ot->invoke = cachefile_open_invoke;
+ ot->exec = cachefile_open_exec;
+ ot->cancel = open_cancel;
+
+ WM_operator_properties_filesel(ot, FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER,
+ FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+}
+
+/* ***************************** Reload Operator **************************** */
+
+static int cachefile_reload_exec(bContext *C, wmOperator *op)
+{
+ CacheFile *cache_file = CTX_data_edit_cachefile(C);
+
+ if (!cache_file) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Main *bmain = CTX_data_main(C);
+
+ BLI_listbase_clear(&cache_file->object_paths);
+ BKE_cachefile_reload(bmain, cache_file);
+
+ return OPERATOR_FINISHED;
+
+ UNUSED_VARS(op);
+}
+
+void CACHEFILE_OT_reload(wmOperatorType *ot)
+{
+ ot->name = "Refresh Archive";
+ ot->description = "Update objects paths list with new data from the archive";
+ ot->idname = "CACHEFILE_OT_reload";
+
+ /* api callbacks */
+ ot->exec = cachefile_reload_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/io/io_cache.h b/source/blender/editors/io/io_cache.h
new file mode 100644
index 00000000000..ea270c2aba1
--- /dev/null
+++ b/source/blender/editors/io/io_cache.h
@@ -0,0 +1,37 @@
+/*
+ * ***** 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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef __IO_CACHE_H__
+#define __IO_CACHE_H__
+
+/** \file blender/editors/io/io_cache.h
+ * \ingroup editor/io
+ */
+
+struct wmOperatorType;
+
+void CACHEFILE_OT_open(struct wmOperatorType *ot);
+void CACHEFILE_OT_reload(struct wmOperatorType *ot);
+
+#endif /* __IO_CACHE_H__ */
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index a70a51a60be..d1e933517a9 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -30,11 +30,18 @@
#include "io_ops.h" /* own include */
+#include "WM_api.h"
+
#ifdef WITH_COLLADA
# include "io_collada.h"
-# include "WM_api.h"
#endif
+#ifdef WITH_ALEMBIC
+# include "io_alembic.h"
+#endif
+
+#include "io_cache.h"
+
void ED_operatortypes_io(void)
{
#ifdef WITH_COLLADA
@@ -42,4 +49,11 @@ void ED_operatortypes_io(void)
WM_operatortype_append(WM_OT_collada_export);
WM_operatortype_append(WM_OT_collada_import);
#endif
+#ifdef WITH_ALEMBIC
+ WM_operatortype_append(WM_OT_alembic_import);
+ WM_operatortype_append(WM_OT_alembic_export);
+#endif
+
+ WM_operatortype_append(CACHEFILE_OT_open);
+ WM_operatortype_append(CACHEFILE_OT_reload);
}
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index cc628210e20..a8b0c28599d 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -48,6 +48,7 @@
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
#include "DNA_actuator_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -1145,10 +1146,22 @@ static int object_delete_exec(bContext *C, wmOperator *op)
}
else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) {
BKE_reportf(op->reports, RPT_WARNING,
- "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
- base->object->id.name + 2, scene->id.name + 2);
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ base->object->id.name + 2, scene->id.name + 2);
continue;
}
+ /* remove from Grease Pencil parent */
+ for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->parent != NULL) {
+ Object *ob = gpl->parent;
+ Object *curob = base->object;
+ if (ob == curob) {
+ gpl->parent = NULL;
+ }
+ }
+ }
+ }
/* deselect object -- it could be used in other scenes */
base->object->flag &= ~SELECT;
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index db8a4c1960f..59d78f13ccb 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -416,6 +416,13 @@ static void test_constraint(Object *owner, bPoseChannel *pchan, bConstraint *con
if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
con->flag |= CONSTRAINT_DISABLE;
}
+ else if (con->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) {
+ bTransformCacheConstraint *data = con->data;
+
+ if ((data->cache_file == NULL) || (data->object_path[0] == '\0')) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
/* Check targets for constraints */
if (check_targets && cti && cti->get_constraint_targets) {
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index b3edf1f5e0d..d5c7632765f 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -48,6 +48,7 @@
#include "DNA_world_types.h"
#include "DNA_object_types.h"
#include "DNA_vfont_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -1381,7 +1382,7 @@ static int move_to_layer_exec(bContext *C, wmOperator *op)
/* upper byte is used for local view */
local = base->lay & 0xFF000000;
base->lay = lay + local;
- base->object->lay = lay;
+ base->object->lay = base->lay;
/* if (base->object->type == OB_LAMP) is_lamp = true; */
}
CTX_DATA_END;
@@ -1762,6 +1763,17 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
else {
/* copy already clears */
}
+ /* 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;
+ }
+ }
+ }
+
base->flag = obn->flag;
id_us_min(&ob->id);
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 992b827113d..85c05ab0e5c 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -43,6 +43,7 @@
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
#include "BKE_camera.h"
#include "BKE_context.h"
@@ -414,6 +415,99 @@ 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])
+{
+ /* d = s + (1-alpha_s)d*/
+ float mul;
+
+ mul = 1.0f - source[3];
+
+ dest[0] = (mul * dest[0]) + source[0];
+ dest[1] = (mul * dest[1]) + source[1];
+ dest[2] = (mul * dest[2]) + source[2];
+ dest[3] = (mul * dest[3]) + source[3];
+
+}
+
+/* add renderlayer and renderpass for each grease pencil layer for using in composition */
+static void add_gpencil_renderpass(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;
+ }
+
+ /* 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(oglrender, rr);
+
+ /* add RendePass composite */
+ RenderPass *rp = RE_create_gp_pass(rr, gpl->info, rv->name);
+
+ /* copy image data from rectf */
+ float *src = RE_RenderViewGetById(rr, oglrender->view_id)->rectf;
+ float *dest = rp->rect;
+
+ float *pixSrc, *pixDest;
+ int x, y, rectx, recty;
+ rectx = rr->rectx;
+ recty = rr->recty;
+ for (y = 0; y < recty; y++) {
+ for (x = 0; x < rectx; x++) {
+ pixSrc = src + 4 * (rectx * y + x);
+ if (pixSrc[3] > 0.0) {
+ pixDest = dest + 4 * (rectx * y + x);
+ addAlphaOverFloat(pixDest, pixSrc);
+ }
+ }
+ }
+
+ /* 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(OGLRender *oglrender)
{
RenderResult *rr;
@@ -449,6 +543,9 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
BLI_assert(view_id < oglrender->views_len);
RE_SetActiveRenderView(oglrender->re, rv->name);
oglrender->view_id = view_id;
+ /* add grease pencil passes */
+ add_gpencil_renderpass(oglrender, rr, rv);
+ /* render composite */
screen_opengl_render_doit(oglrender, rr);
}
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 76d0143e898..b4f3426677a 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -1210,7 +1210,7 @@ void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *r
/* setup job */
WM_jobs_customdata_set(wm_job, ip, icon_preview_free);
- WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL);
+ WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index f61ad348501..34c51914027 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -85,7 +85,8 @@ 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_layer", "active_gpencil_frame", "active_gpencil_palette",
+ "active_gpencil_palettecolor", "active_gpencil_brush",
"active_operator",
NULL};
@@ -116,7 +117,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "visible_objects") || CTX_data_equals(member, "visible_bases")) {
const unsigned int lay = context_layers(sc, scene, sa);
- int visible_objects = CTX_data_equals(member, "visible_objects");
+ const bool visible_objects = CTX_data_equals(member, "visible_objects");
for (base = scene->base.first; base; base = base->next) {
if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & lay)) {
@@ -131,7 +132,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "selectable_objects") || CTX_data_equals(member, "selectable_bases")) {
const unsigned int lay = context_layers(sc, scene, sa);
- int selectable_objects = CTX_data_equals(member, "selectable_objects");
+ const bool selectable_objects = CTX_data_equals(member, "selectable_objects");
for (base = scene->base.first; base; base = base->next) {
if (base->lay & lay) {
@@ -148,7 +149,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "selected_objects") || CTX_data_equals(member, "selected_bases")) {
const unsigned int lay = context_layers(sc, scene, sa);
- int selected_objects = CTX_data_equals(member, "selected_objects");
+ const bool selected_objects = CTX_data_equals(member, "selected_objects");
for (base = scene->base.first; base; base = base->next) {
if ((base->flag & SELECT) && (base->lay & lay)) {
@@ -163,7 +164,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "selected_editable_objects") || CTX_data_equals(member, "selected_editable_bases")) {
const unsigned int lay = context_layers(sc, scene, sa);
- int selected_editable_objects = CTX_data_equals(member, "selected_editable_objects");
+ const bool selected_editable_objects = CTX_data_equals(member, "selected_editable_objects");
for (base = scene->base.first; base; base = base->next) {
if ((base->flag & SELECT) && (base->lay & lay)) {
@@ -182,7 +183,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "editable_objects") || CTX_data_equals(member, "editable_bases")) {
const unsigned int lay = context_layers(sc, scene, sa);
- int editable_objects = CTX_data_equals(member, "editable_objects");
+ const bool editable_objects = CTX_data_equals(member, "editable_objects");
/* Visible + Editable, but not necessarily selected */
for (base = scene->base.first; base; base = base->next) {
@@ -201,7 +202,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
else if (CTX_data_equals(member, "visible_bones") || CTX_data_equals(member, "editable_bones")) {
bArmature *arm = (obedit && obedit->type == OB_ARMATURE) ? obedit->data : NULL;
EditBone *ebone, *flipbone = NULL;
- int editable_bones = CTX_data_equals(member, "editable_bones");
+ const bool editable_bones = CTX_data_equals(member, "editable_bones");
if (arm && arm->edbo) {
/* Attention: X-Axis Mirroring is also handled here... */
@@ -243,7 +244,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
else if (CTX_data_equals(member, "selected_bones") || CTX_data_equals(member, "selected_editable_bones")) {
bArmature *arm = (obedit && obedit->type == OB_ARMATURE) ? obedit->data : NULL;
EditBone *ebone, *flipbone = NULL;
- int selected_editable_bones = CTX_data_equals(member, "selected_editable_bones");
+ const bool selected_editable_bones = CTX_data_equals(member, "selected_editable_bones");
if (arm && arm->edbo) {
/* Attention: X-Axis Mirroring is also handled here... */
@@ -466,7 +467,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
if (gpd) {
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
if (gpl) {
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl);
@@ -474,12 +475,50 @@ 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);
+
+ if (brush) {
+ CTX_data_pointer_set(result, NULL, &RNA_GPencilBrush, 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);
if (gpd) {
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
if (gpl) {
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl->actframe);
@@ -533,6 +572,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
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;
+ }
+
CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps);
}
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index f0a6b56a7d2..ac39c6f995c 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -1943,6 +1943,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
sc = ED_screen_add(win, oldscreen->scene, newname);
sc->state = state;
sc->redraws_flag = oldscreen->redraws_flag;
+ sc->temp = oldscreen->temp;
/* timer */
sc->animtimer = oldscreen->animtimer;
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 080bd5b73c7..9474a46d716 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -1126,8 +1126,8 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
/* blend into canvas */
for (a = 0; a < tot; a++) {
ED_imapaint_dirty_region(s->image, s->canvas,
- region[a].destx, region[a].desty,
- region[a].width, region[a].height, true);
+ region[a].destx, region[a].desty,
+ region[a].width, region[a].height, true);
if (s->do_masking) {
/* masking, find original pixels tiles from undo buffer to composite over */
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 1305b76b5ad..fe0fb3f5035 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1239,7 +1239,7 @@ static float brush_strength(
/* Return a multiplier for brush strength on a particular vertex. */
static float tex_strength(SculptSession *ss, Brush *br,
- const float point[3],
+ const float brush_point[3],
const float len,
const short vno[3],
const float fno[3],
@@ -1251,6 +1251,9 @@ static float tex_strength(SculptSession *ss, Brush *br,
MTex *mtex = &br->mtex;
float avg = 1;
float rgba[4];
+ float point[3];
+
+ sub_v3_v3v3(point, brush_point, cache->plane_offset);
if (!mtex->tex) {
avg = 1;
diff --git a/source/blender/editors/space_action/action_buttons.c b/source/blender/editors/space_action/action_buttons.c
index 063a477d2b6..bfc808f6d83 100644
--- a/source/blender/editors/space_action/action_buttons.c
+++ b/source/blender/editors/space_action/action_buttons.c
@@ -122,7 +122,7 @@ void ACTION_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
ot->idname = "ACTION_OT_properties";
- ot->description = "Toggle display properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->exec = action_properties_toggle_exec;
ot->poll = ED_operator_action_active;
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 55b087c40e7..f8db35e2311 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -750,7 +750,7 @@ static void insert_gpencil_keys(bAnimContext *ac, short mode)
/* insert gp frames */
for (ale = anim_data.first; ale; ale = ale->next) {
bGPDlayer *gpl = (bGPDlayer *)ale->data;
- gpencil_layer_getframe(gpl, CFRA, add_frame_mode);
+ BKE_gpencil_layer_getframe(gpl, CFRA, add_frame_mode);
}
ANIM_animdata_update(ac, &anim_data);
diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c
index d31d7f53b30..b042bbe8fea 100644
--- a/source/blender/editors/space_clip/clip_toolbar.c
+++ b/source/blender/editors/space_clip/clip_toolbar.c
@@ -106,7 +106,7 @@ void CLIP_OT_properties(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Properties";
- ot->description = "Toggle clip properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->idname = "CLIP_OT_properties";
/* api callbacks */
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 415839ab761..396d71f0a20 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -818,7 +818,7 @@ static void clip_keymap(struct wmKeyConfig *keyconf)
keymap = WM_keymap_find(keyconf, "Clip Dopesheet Editor", SPACE_CLIP, 0);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_dopesheet_select_channel", ACTIONMOUSE, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "CLIP_OT_dopesheet_select_channel", LEFTMOUSE, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "extend", true); /* toggle */
WM_keymap_add_item(keymap, "CLIP_OT_dopesheet_view_all", HOMEKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 5e9eb1f9207..b6e4991bf52 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -920,6 +920,8 @@ static int filelist_geticon_ex(
return ICON_FILE_BLANK;
else if (typeflag & FILE_TYPE_COLLADA)
return ICON_FILE_BLANK;
+ else if (typeflag & FILE_TYPE_ALEMBIC)
+ return ICON_FILE_BLANK;
else if (typeflag & FILE_TYPE_TEXT)
return ICON_FILE_TEXT;
else if (typeflag & FILE_TYPE_BLENDERLIB) {
@@ -1952,6 +1954,9 @@ int ED_path_extension_type(const char *path)
else if (BLI_testextensie(path, ".dae")) {
return FILE_TYPE_COLLADA;
}
+ else if (BLI_testextensie(path, ".abc")) {
+ return FILE_TYPE_ALEMBIC;
+ }
else if (BLI_testextensie_array(path, imb_ext_image) ||
(G.have_quicktime && BLI_testextensie_array(path, imb_ext_image_qt)))
{
@@ -2004,6 +2009,8 @@ int ED_file_extension_icon(const char *path)
return ICON_FILE_BLANK;
case FILE_TYPE_COLLADA:
return ICON_FILE_BLANK;
+ case FILE_TYPE_ALEMBIC:
+ return ICON_FILE_BLANK;
case FILE_TYPE_TEXT:
return ICON_FILE_TEXT;
default:
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index ab33d452d3c..1a558d40560 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -185,6 +185,8 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BTX : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_collada")))
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_COLLADA : 0;
+ if ((prop = RNA_struct_find_property(op->ptr, "filter_alembic")))
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_ALEMBIC : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_glob"))) {
/* Protection against pyscripts not setting proper size limit... */
char *tmp = RNA_property_string_get_alloc(
@@ -213,7 +215,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | FILTER_ID_LT | FILTER_ID_MA |
FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB |
FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO |
- FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO;
+ FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF;
if (U.uiflag & USER_HIDE_DOT) {
params->flag |= FILE_HIDE_DOT;
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index a9ab1502e16..516814b63b4 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -812,6 +812,11 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
}
col = uiLayoutColumn(pa->layout, true);
+
+ if (driver->type == DRIVER_TYPE_PYTHON) {
+ uiItemR(col, &driver_ptr, "use_self", 0, NULL, ICON_NONE);
+ }
+
/* debug setting */
uiItemR(col, &driver_ptr, "show_debug_info", 0, NULL, ICON_NONE);
@@ -1062,7 +1067,7 @@ void GRAPH_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
ot->idname = "GRAPH_OT_properties";
- ot->description = "Toggle display properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->exec = graph_properties_toggle_exec;
ot->poll = ED_operator_graphedit_active;
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 38a54ade367..b9d98dfe794 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -1330,7 +1330,7 @@ void IMAGE_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
ot->idname = "IMAGE_OT_properties";
- ot->description = "Toggle display properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->exec = image_properties_toggle_exec;
ot->poll = ED_operator_image_active;
diff --git a/source/blender/editors/space_logic/logic_buttons.c b/source/blender/editors/space_logic/logic_buttons.c
index 12c7ef3d3ec..e5eee21ed08 100644
--- a/source/blender/editors/space_logic/logic_buttons.c
+++ b/source/blender/editors/space_logic/logic_buttons.c
@@ -63,7 +63,7 @@ static int logic_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void LOGIC_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
- ot->description = "Toggle display properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->idname = "LOGIC_OT_properties";
ot->exec = logic_properties_toggle_exec;
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index cbdc476bee6..3243579f7d0 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -131,6 +131,7 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
@@ -567,7 +568,7 @@ void NLA_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
ot->idname = "NLA_OT_properties";
- ot->description = "Toggle display properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->exec = nla_properties_toggle_exec;
ot->poll = ED_operator_nla_active;
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 9e73e03a664..4f30c049d9d 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -170,6 +170,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index d40240e8412..f3d2bf2662a 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -1337,7 +1337,7 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point
scn_ptr = RNA_pointer_get(ptr, "scene");
RNA_string_get(&scn_ptr, "name", scene_name);
-
+
WM_operator_properties_create_ptr(&op_ptr, ot);
RNA_string_set(&op_ptr, "layer", layer_name);
RNA_string_set(&op_ptr, "scene", scene_name);
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index 52b0292b9a3..f0567924edd 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -222,7 +222,7 @@ static int node_properties_poll(bContext *C)
void NODE_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
- ot->description = "Toggles the properties panel display";
+ ot->description = "Toggle the properties region visibility";
ot->idname = "NODE_OT_properties";
ot->exec = node_properties_toggle_exec;
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index cf6e2ac226e..26eeaa91dd0 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -794,22 +794,37 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
link->tosock = node_group_find_input_socket(gnode, iosock->identifier);
}
else if (fromselect) {
- bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link->fromnode, link->fromsock);
- bNodeSocket *output_sock;
-
- /* update the group node and interface node sockets,
- * so the new interface socket can be linked.
- */
- node_group_verify(ntree, gnode, (ID *)ngroup);
- node_group_output_verify(ngroup, output_node, (ID *)ngroup);
+ /* First check whether the source of this link is already connected to an output.
+ * If yes, reuse that output instead of duplicating it. */
+ bool connected = false;
+ bNodeLink *olink;
+ for (olink = ngroup->links.first; olink; olink = olink->next) {
+ if (olink->fromsock == link->fromsock && olink->tonode == output_node) {
+ bNodeSocket *output_sock = node_group_find_output_socket(gnode, olink->tosock->identifier);
+ link->fromnode = gnode;
+ link->fromsock = output_sock;
+ connected = true;
+ }
+ }
- /* create new internal link */
- output_sock = node_group_output_find_socket(output_node, iosock->identifier);
- nodeAddLink(ngroup, link->fromnode, link->fromsock, output_node, output_sock);
-
- /* redirect external link */
- link->fromnode = gnode;
- link->fromsock = node_group_find_output_socket(gnode, iosock->identifier);
+ if (!connected) {
+ bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link->fromnode, link->fromsock);
+ bNodeSocket *output_sock;
+
+ /* update the group node and interface node sockets,
+ * so the new interface socket can be linked.
+ */
+ node_group_verify(ntree, gnode, (ID *)ngroup);
+ node_group_output_verify(ngroup, output_node, (ID *)ngroup);
+
+ /* create new internal link */
+ output_sock = node_group_output_find_socket(output_node, iosock->identifier);
+ nodeAddLink(ngroup, link->fromnode, link->fromsock, output_node, output_sock);
+
+ /* redirect external link */
+ link->fromnode = gnode;
+ link->fromsock = node_group_find_output_socket(gnode, iosock->identifier);
+ }
}
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index ae34a118992..d4553b650c5 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -1002,7 +1002,7 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
}
-static void tselem_draw_gp_icon_uibut(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl)
+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) {
@@ -1173,6 +1173,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
UI_icon_draw(x, y, ICON_MOD_TRIANGULATE); break;
case eModifierType_MeshCache:
UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
+ case eModifierType_MeshSequenceCache:
+ UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
case eModifierType_Wireframe:
UI_icon_draw(x, y, ICON_MOD_WIREFRAME); break;
case eModifierType_LaplacianDeform:
@@ -1233,9 +1235,12 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
else
UI_icon_draw(x, y, RNA_struct_ui_icon(te->rnaptr.type));
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);
break;
+#endif
default:
UI_icon_draw(x, y, ICON_DOT); break;
}
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index d2666cd0b6d..ca037cb20cc 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -62,7 +62,7 @@ typedef struct TreeElement {
#define TREESTORE_ID_TYPE(_id) \
(ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_NT, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \
ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS) || \
- ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO)) /* Only in 'blendfile' mode ... :/ */
+ ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO, ID_CF)) /* Only in 'blendfile' mode ... :/ */
/* TreeElement->flag */
#define TE_ACTIVE 1
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index b22e6595caf..96bab3d5c1e 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -38,6 +38,7 @@
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_camera_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_key_types.h"
@@ -746,6 +747,16 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
outliner_add_element(soops, &te->subtree, ca, te, TSE_ANIM_DATA, 0);
break;
}
+ case ID_CF:
+ {
+ CacheFile *cache_file = (CacheFile *)id;
+
+ if (outliner_animdata_test(cache_file->adt)) {
+ outliner_add_element(soops, &te->subtree, cache_file, te, TSE_ANIM_DATA, 0);
+ }
+
+ break;
+ }
case ID_LA:
{
Lamp *la = (Lamp *)id;
diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c
index 86d3fcbe1ac..b33a26db728 100644
--- a/source/blender/editors/space_sequencer/sequencer_buttons.c
+++ b/source/blender/editors/space_sequencer/sequencer_buttons.c
@@ -94,7 +94,7 @@ void SEQUENCER_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
ot->idname = "SEQUENCER_OT_properties";
- ot->description = "Open sequencer properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->exec = sequencer_properties_toggle_exec;
ot->poll = ED_operator_sequencer_active;
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index adb7cf4940c..e1768e4aedc 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -471,7 +471,7 @@ static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_cla
}
/* draw info text on a sequence strip */
-static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float y1, float y2, const unsigned char background_col[3])
+static void draw_seq_text(View2D *v2d, SpaceSeq *sseq, Sequence *seq, float x1, float x2, float y1, float y2, const unsigned char background_col[3])
{
rctf rect;
char str[32 + FILE_MAX];
@@ -540,7 +540,12 @@ static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float
name, seq->len);
}
else if (seq->type == SEQ_TYPE_SOUND_RAM) {
- if (seq->sound) {
+ /* If a waveform is drawn, we don't want to overlay it with text,
+ * as it would make both hard to read. */
+ if ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM)) {
+ str[0] = 0;
+ str_len = 0;
+ } else if (seq->sound) {
str_len = BLI_snprintf(str, sizeof(str), "%s: %s | %d",
name, seq->sound->name, seq->len);
}
@@ -870,7 +875,7 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg
/* nice text here would require changing the view matrix for texture text */
if ((x2 - x1) / pixelx > 32) {
- draw_seq_text(v2d, seq, x1, x2, y1, y2, background_col);
+ draw_seq_text(v2d, sseq, seq, x1, x2, y1, y2, background_col);
}
}
diff --git a/source/blender/editors/space_text/text_header.c b/source/blender/editors/space_text/text_header.c
index 91665f1a598..e06a5b5474e 100644
--- a/source/blender/editors/space_text/text_header.c
+++ b/source/blender/editors/space_text/text_header.c
@@ -92,7 +92,7 @@ void TEXT_OT_properties(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Properties";
- ot->description = "Toggle text properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->idname = "TEXT_OT_properties";
/* api callbacks */
diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c
index fde955c24a7..021c4a54b0a 100644
--- a/source/blender/editors/space_time/space_time.c
+++ b/source/blender/editors/space_time/space_time.c
@@ -32,7 +32,10 @@
#include <string.h>
#include <stdio.h>
+#include "DNA_cachefile_types.h"
+#include "DNA_constraint_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -42,7 +45,10 @@
#include "BLI_dlrbTree.h"
#include "BLI_utildefines.h"
+#include "BKE_constraint.h"
#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
#include "BKE_screen.h"
#include "BKE_pointcache.h"
@@ -320,6 +326,9 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
case ID_GD:
gpencil_to_keylist(&ads, (bGPdata *)id, &keys);
break;
+ case ID_CF:
+ cachefile_to_keylist(&ads, (CacheFile *)id, &keys, NULL);
+ break;
}
/* build linked-list for searching */
@@ -344,6 +353,56 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
BLI_dlrbTree_free(&keys);
}
+static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, bool onlysel)
+{
+ CacheFile *cache_file;
+
+ for (cache_file = bmain->cachefiles.first;
+ cache_file;
+ cache_file = cache_file->id.next)
+ {
+ cache_file->draw_flag &= ~CACHEFILE_KEYFRAME_DRAWN;
+ }
+
+ for (Base *base = scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
+
+ if (md) {
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+
+ cache_file = mcmd->cache_file;
+
+ if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
+ continue;
+ }
+
+ cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
+
+ time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel);
+ }
+
+ for (bConstraint *con = ob->constraints.first; con; con = con->next) {
+ if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
+ continue;
+ }
+
+ bTransformCacheConstraint *data = con->data;
+
+ cache_file = data->cache_file;
+
+ if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
+ continue;
+ }
+
+ cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
+
+ time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel);
+ }
+ }
+}
+
/* draw keyframe lines for timeline */
static void time_draw_keyframes(const bContext *C, ARegion *ar)
{
@@ -354,7 +413,11 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar)
/* set this for all keyframe lines once and for all */
glLineWidth(1.0);
-
+
+ /* draw cache files keyframes (if available) */
+ UI_ThemeColor(TH_TIME_KEYFRAME);
+ time_draw_caches_keyframes(CTX_data_main(C), scene, v2d, onlysel);
+
/* draw grease pencil keyframes (if available) */
UI_ThemeColor(TH_TIME_GP_KEYFRAME);
if (scene->gpd) {
@@ -585,6 +648,10 @@ static void time_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa),
break;
}
break;
+ case NC_GPENCIL:
+ if (wmn->data == ND_DATA)
+ ED_region_tag_redraw(ar);
+ break;
}
}
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index f5289a0d245..74a50497164 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -435,12 +435,16 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
else {
/* draw with lights in the scene otherwise */
solidtex = false;
- if (v3d->flag2 & V3D_SHADELESS_TEX)
+ if (v3d->flag2 & V3D_SHADELESS_TEX) {
Gtexdraw.is_lit = 0;
- else
- Gtexdraw.is_lit = GPU_scene_object_lights(scene, ob, v3d->lay, rv3d->viewmat, !rv3d->is_persp);
+ }
+ else {
+ Gtexdraw.is_lit = GPU_scene_object_lights(
+ scene, ob, v3d->localvd ? v3d->localvd->lay : v3d->lay,
+ rv3d->viewmat, !rv3d->is_persp);
+ }
}
-
+
rgba_float_to_uchar(obcol, ob->col);
if (solidtex || v3d->drawtype == OB_TEXTURE) is_tex = true;
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 4320699b8d7..47390578573 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -4663,7 +4663,7 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
index3_nors_incr = true;
}
else {
- if (!render_only || (render_only && BKE_displist_has_faces(lb))) {
+ if (!render_only || BKE_displist_has_faces(lb)) {
return drawDispListwire(lb, ob->type);
}
}
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index e93d840eddd..8dbc2788744 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -379,11 +379,13 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
/* setup buffer and draw */
- int gl_depth = 0, gl_blend = 0;
+ int gl_depth = 0, gl_blend = 0, gl_depth_write = 0;
glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
+ glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&gl_depth_write);
glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
@@ -422,6 +424,8 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
GPU_shader_unbind();
+ glDepthMask(gl_depth_write);
+
if (!gl_blend) {
glDisable(GL_BLEND);
}
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 96dda65b81d..075b1faf502 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -1414,7 +1414,9 @@ static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_i
if ((ID *)v3d->camera == old_id) {
v3d->camera = (Object *)new_id;
if (!new_id) {
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ /* 3D view might be inactive, in that case needs to use slink->regionbase */
+ ListBase *regionbase = (slink == sa->spacedata.first) ? &sa->regionbase : &slink->regionbase;
+ for (ar = regionbase->first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = is_local ? ((RegionView3D *)ar->regiondata)->localvd : ar->regiondata;
if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index c52d1238163..b9c8c98b62f 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -1206,7 +1206,7 @@ static int view3d_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void VIEW3D_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
- ot->description = "Toggles the properties panel display";
+ ot->description = "Toggle the properties region visibility";
ot->idname = "VIEW3D_OT_properties";
ot->exec = view3d_properties_toggle_exec;
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index b117a5e68d8..215d90a8878 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -4518,7 +4518,7 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot)
/* note: having key shortcut here is bad practice,
* but for now keep because this displays when dragging an image over the 3D viewport */
ot->name = "Add Background Image (Ctrl for Empty Object)";
- ot->description = "Add a new background image";
+ ot->description = "Add a new background image (Ctrl for Empty Object)";
ot->idname = "VIEW3D_OT_background_image_add";
/* api callbacks */
@@ -4527,7 +4527,7 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot)
ot->poll = ED_operator_view3d_active;
/* flags */
- ot->flag = 0;
+ ot->flag = OPTYPE_UNDO;
/* properties */
RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign");
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index f46608b7d5e..37b068e3e49 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -302,18 +302,18 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
bool changed = false;
if (scene->gpd == NULL) {
- scene->gpd = gpencil_data_addnew("GPencil");
+ scene->gpd = BKE_gpencil_data_addnew("GPencil");
}
gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
if (gpl == NULL) {
- gpl = gpencil_layer_addnew(scene->gpd, ruler_name, false);
+ gpl = BKE_gpencil_layer_addnew(scene->gpd, ruler_name, false);
gpl->thickness = 1;
gpl->flag |= GP_LAYER_HIDE;
}
- gpf = gpencil_layer_getframe(gpl, CFRA, true);
- free_gpencil_strokes(gpf);
+ gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
+ BKE_gpencil_free_strokes(gpf);
for (ruler_item = ruler_info->items.first; ruler_item; ruler_item = ruler_item->next) {
bGPDspoint *pt;
@@ -327,6 +327,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
for (j = 0; j < 3; j++) {
copy_v3_v3(&pt->x, ruler_item->co[j]);
pt->pressure = 1.0f;
+ pt->strength = 1.0f;
pt++;
}
}
@@ -336,6 +337,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
for (j = 0; j < 3; j += 2) {
copy_v3_v3(&pt->x, ruler_item->co[j]);
pt->pressure = 1.0f;
+ pt->strength = 1.0f;
pt++;
}
}
@@ -358,7 +360,7 @@ static bool view3d_ruler_from_gpencil(bContext *C, RulerInfo *ruler_info)
gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
if (gpl) {
bGPDframe *gpf;
- gpf = gpencil_layer_getframe(gpl, CFRA, false);
+ gpf = BKE_gpencil_layer_getframe(gpl, CFRA, false);
if (gpf) {
bGPDstroke *gps;
for (gps = gpf->strokes.first; gps; gps = gps->next) {
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index f18493e4b34..ef6cff19181 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -51,6 +51,7 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_ghash.h"
+#include "BLI_stackdefines.h"
#include "BLI_memarena.h"
#include "BKE_nla.h"
@@ -3719,19 +3720,10 @@ static void initRotation(TransInfo *t)
copy_v3_v3(t->axis_orig, t->axis);
}
-static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around)
+static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], const float *center)
{
float vec[3], totmat[3][3], smat[3][3];
float eul[3], fmat[3][3], quat[4];
- const float *center;
-
- /* local constraint shouldn't alter center */
- if (transdata_check_local_center(t, around)) {
- center = td->center;
- }
- else {
- center = t->center;
- }
if (t->flag & T_POINTS) {
mul_m3_m3m3(totmat, mat, td->mtx);
@@ -3941,6 +3933,21 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
}
}
+static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const short around)
+{
+ const float *center;
+
+ /* local constraint shouldn't alter center */
+ if (transdata_check_local_center(t, around)) {
+ center = td->center;
+ }
+ else {
+ center = t->center;
+ }
+
+ ElementRotation_ex(t, td, mat, center);
+}
+
static void applyRotationValue(TransInfo *t, float angle, float axis[3])
{
TransData *td = t->data;
@@ -3990,10 +3997,8 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
applySnapping(t, &final);
- if (applyNumInput(&t->num, &final)) {
- /* Clamp between -PI and PI */
- final = angle_wrap_rad(final);
- }
+ /* Used to clamp final result in [-PI, PI[ range, no idea why, inheritance from 2.4x area, see T48998. */
+ applyNumInput(&t->num, &final);
t->values[0] = final;
@@ -4341,12 +4346,16 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
if (td->flag & TD_SKIP)
continue;
+ float rotate_offset[3] = {0};
+ bool use_rotate_offset = false;
+
/* handle snapping rotation before doing the translation */
if (usingSnappingNormal(t)) {
+ float mat[3][3];
+
if (validSnappingNormal(t)) {
const float *original_normal;
- float mat[3][3];
-
+
/* In pose mode, we want to align normals with Y axis of bones... */
if (t->flag & T_POSE)
original_normal = td->axismtx[1];
@@ -4354,18 +4363,19 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
original_normal = td->axismtx[2];
rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal);
-
- ElementRotation(t, td, mat, V3D_AROUND_LOCAL_ORIGINS);
}
else {
- float mat[3][3];
-
unit_m3(mat);
-
- ElementRotation(t, td, mat, V3D_AROUND_LOCAL_ORIGINS);
+ }
+
+ ElementRotation_ex(t, td, mat, t->tsnap.snapTarget);
+
+ if (td->loc) {
+ use_rotate_offset = true;
+ sub_v3_v3v3(rotate_offset, td->loc, td->iloc);
}
}
-
+
if (t->con.applyVec) {
float pvec[3];
t->con.applyVec(t, td, vec, tvec, pvec);
@@ -4373,6 +4383,10 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
else {
copy_v3_v3(tvec, vec);
}
+
+ if (use_rotate_offset) {
+ add_v3_v3(tvec, rotate_offset);
+ }
mul_m3_v3(td->smtx, tvec);
mul_v3_fl(tvec, td->factor);
@@ -4381,7 +4395,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
if (td->loc)
add_v3_v3v3(td->loc, td->iloc, tvec);
-
+
constraintTransLim(t, td);
}
}
@@ -5893,7 +5907,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
*/
static void calcEdgeSlide_mval_range(
TransInfo *t, EdgeSlideData *sld, const int *sv_table, const int loop_nr,
- const float mval[2], const bool use_btree_disp, const bool use_calc_direction)
+ const float mval[2], const bool use_occlude_geometry, const bool use_calc_direction)
{
TransDataEdgeSlideVert *sv_array = sld->sv;
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
@@ -5902,7 +5916,7 @@ static void calcEdgeSlide_mval_range(
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
float projectMat[4][4];
- BMBVHTree *btree;
+ BMBVHTree *bmbvh;
/* only for use_calc_direction */
float (*loop_dir)[3] = NULL, *loop_maxdist = NULL;
@@ -5926,11 +5940,11 @@ static void calcEdgeSlide_mval_range(
ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
}
- if (use_btree_disp) {
- btree = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false);
+ if (use_occlude_geometry) {
+ bmbvh = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false);
}
else {
- btree = NULL;
+ bmbvh = NULL;
}
/* find mouse vectors, the global one, and one per loop in case we have
@@ -5965,7 +5979,7 @@ static void calcEdgeSlide_mval_range(
continue;
/* This test is only relevant if object is not wire-drawn! See [#32068]. */
- if (use_btree_disp && !BMBVH_EdgeVisible(btree, e_other, ar, v3d, t->obedit)) {
+ if (use_occlude_geometry && !BMBVH_EdgeVisible(bmbvh, e_other, ar, v3d, t->obedit)) {
continue;
}
@@ -6046,8 +6060,8 @@ static void calcEdgeSlide_mval_range(
sld->mval_end[0] = t->mval[0] + mval_end[0];
sld->mval_end[1] = t->mval[1] + mval_end[1];
- if (btree) {
- BKE_bmbvh_free(btree);
+ if (bmbvh) {
+ BKE_bmbvh_free(bmbvh);
}
}
@@ -6109,8 +6123,8 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
int *sv_table; /* BMVert -> sv_array index */
EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
- int numsel, i, j, loop_nr;
- bool use_btree_disp = false;
+ int numsel, i, loop_nr;
+ bool use_occlude_geometry = false;
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
@@ -6157,31 +6171,39 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__);
- j = 0;
- BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- sv_table[i] = j;
- j += 1;
- }
- else {
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- sv_table[i] = -1;
+#define INDEX_UNSET -1
+#define INDEX_INVALID -2
+
+ {
+ int j = 0;
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ sv_table[i] = INDEX_UNSET;
+ j += 1;
+ }
+ else {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ sv_table[i] = INDEX_INVALID;
+ }
+ BM_elem_index_set(v, i); /* set_inline */
}
- BM_elem_index_set(v, i); /* set_inline */
- }
- bm->elem_index_dirty &= ~BM_VERT;
+ bm->elem_index_dirty &= ~BM_VERT;
- if (!j) {
- MEM_freeN(sld);
- MEM_freeN(sv_table);
- return false;
+ if (!j) {
+ MEM_freeN(sld);
+ MEM_freeN(sv_table);
+ return false;
+ }
+ sv_tot = j;
}
- sv_tot = j;
sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * sv_tot, "sv_array");
loop_nr = 0;
+ STACK_DECLARE(sv_array);
+ STACK_INIT(sv_array, sv_tot);
+
while (1) {
float vec_a[3], vec_b[3];
BMLoop *l_a, *l_b;
@@ -6274,6 +6296,11 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
l_a_prev = NULL;
l_b_prev = NULL;
+#define SV_FROM_VERT(v) ( \
+ (sv_table[BM_elem_index_get(v)] == INDEX_UNSET) ? \
+ ((void)(sv_table[BM_elem_index_get(v)] = STACK_SIZE(sv_array)), STACK_PUSH_RET_PTR(sv_array)) : \
+ (&sv_array[sv_table[BM_elem_index_get(v)]]))
+
/*iterate over the loop*/
v_first = v;
do {
@@ -6285,8 +6312,8 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
/* XXX, 'sv' will initialize multiple times, this is suspicious. see [#34024] */
BLI_assert(v != NULL);
- BLI_assert(sv_table[BM_elem_index_get(v)] != -1);
- sv = &sv_array[sv_table[BM_elem_index_get(v)]];
+ BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID);
+ sv = SV_FROM_VERT(v);
sv->v = v;
copy_v3_v3(sv->v_co_orig, v->co);
sv->loop_nr = loop_nr;
@@ -6311,8 +6338,10 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
if (!e) {
BLI_assert(v != NULL);
- BLI_assert(sv_table[BM_elem_index_get(v)] != -1);
- sv = &sv_array[sv_table[BM_elem_index_get(v)]];
+
+ BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID);
+ sv = SV_FROM_VERT(v);
+
sv->v = v;
copy_v3_v3(sv->v_co_orig, v->co);
sv->loop_nr = loop_nr;
@@ -6401,6 +6430,10 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
BM_elem_flag_disable(v_prev, BM_ELEM_TAG);
} while ((e != v_first->e) && (l_a || l_b));
+#undef SV_FROM_VERT
+#undef INDEX_UNSET
+#undef INDEX_INVALID
+
loop_nr++;
#undef EDGESLIDE_VERT_IS_INNER
@@ -6408,6 +6441,8 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
/* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
+ BLI_assert(STACK_SIZE(sv_array) == sv_tot);
+
sld->sv = sv_array;
sld->totsv = sv_tot;
@@ -6415,10 +6450,10 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
if (t->spacetype == SPACE_VIEW3D) {
v3d = t->sa ? t->sa->spacedata.first : NULL;
rv3d = t->ar ? t->ar->regiondata : NULL;
- use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+ use_occlude_geometry = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
}
- calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_btree_disp, true);
+ calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_occlude_geometry, true);
/* create copies of faces for customdata projection */
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
@@ -6456,7 +6491,7 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
int loop_nr;
- bool use_btree_disp = false;
+ bool use_occlude_geometry = false;
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
@@ -6503,6 +6538,7 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
bm->elem_index_dirty &= ~BM_VERT;
if (!j) {
+ MEM_freeN(sld);
return false;
}
@@ -6617,10 +6653,10 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
if (t->spacetype == SPACE_VIEW3D) {
v3d = t->sa ? t->sa->spacedata.first : NULL;
rv3d = t->ar ? t->ar->regiondata : NULL;
- use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+ use_occlude_geometry = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
}
- calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_btree_disp, false);
+ calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_occlude_geometry, false);
/* create copies of faces for customdata projection */
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 50168e78dda..a59f9dc43dd 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -87,7 +87,6 @@ typedef struct TransSnap {
float snapPoint[3]; /* snapping from this point */
float snapTarget[3]; /* to this point */
float snapNormal[3];
- float snapTangent[3];
char snapNodeBorder;
ListBase points;
TransSnapPoint *selectedPoint;
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index b7456facbdf..9c266890d6d 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -701,7 +701,6 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob)
bPoseChannel *pchan;
Bone *bone;
int mode = *out_mode;
- int hastranslation = 0;
int total = 0;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -729,7 +728,7 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob)
}
}
/* now count, and check if we have autoIK or have to switch from translate to rotate */
- hastranslation = 0;
+ bool has_translation = false, has_rotation = false;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
bone = pchan->bone;
@@ -740,20 +739,29 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob)
if (has_targetless_ik(pchan) == NULL) {
if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM)
- hastranslation = 1;
+ has_translation = true;
}
- else if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC)
- hastranslation = 1;
+ else {
+ if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC)
+ has_translation = true;
+ }
+ if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT)
+ has_rotation = true;
}
else
- hastranslation = 1;
+ has_translation = true;
}
}
}
/* if there are no translatable bones, do rotation */
- if (mode == TFM_TRANSLATION && !hastranslation) {
- *out_mode = TFM_ROTATION;
+ if (mode == TFM_TRANSLATION && !has_translation) {
+ if (has_rotation) {
+ *out_mode = TFM_ROTATION;
+ }
+ else {
+ *out_mode = TFM_RESIZE;
+ }
}
return total;
@@ -3284,7 +3292,7 @@ static void posttrans_gpd_clean(bGPdata *gpd)
for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
gpfn = gpf->next;
if (gpfn && gpf->framenum == gpfn->framenum) {
- gpencil_layer_delframe(gpl, gpf);
+ BKE_gpencil_layer_delframe(gpl, gpf);
}
}
}
@@ -7679,7 +7687,11 @@ static void createTransGPencil(bContext *C, TransInfo *t)
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 (is_prop_edit) {
/* Proportional Editing... */
if (is_prop_edit_connected) {
@@ -7727,14 +7739,27 @@ static void createTransGPencil(bContext *C, TransInfo *t)
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf = gpl->actframe;
bGPDstroke *gps;
+ 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);
+ }
- /* Make a new frame to work on if the layer's frame and the current scene frame don't match up
+ /* 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...
*/
// XXX: should this be allowed when framelock is enabled?
if (gpf->framenum != cfra) {
- gpf = gpencil_frame_addcopy(gpl, cfra);
+ gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
+ /* in some weird situations (framelock enabled) return NULL */
+ if (gpf == NULL) {
+ continue;
+ }
}
/* Loop over strokes, adding TransData for points as needed... */
@@ -7747,7 +7772,10 @@ static void createTransGPencil(bContext *C, TransInfo *t)
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) {
@@ -7816,9 +7844,18 @@ static void createTransGPencil(bContext *C, TransInfo *t)
/* screenspace */
td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
- copy_m3_m4(td->smtx, t->persmat);
- copy_m3_m4(td->mtx, t->persinv);
- unit_m3(td->axismtx);
+ /* 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);
+ }
+ 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... */
@@ -7827,9 +7864,18 @@ static void createTransGPencil(bContext *C, TransInfo *t)
// XXX: matrices may need to be different?
}
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- unit_m3(td->axismtx); // XXX?
+ /* 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 */
+ }
}
/* Triangulation must be calculated again, so save the stroke for recalc function */
td->extra = gps;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 728b10f5e6f..f78a23be7b8 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -975,7 +975,9 @@ static void recalcData_gpencil_strokes(TransInfo *t)
TransData *td = t->data;
for (int i = 0; i < t->total; i++, td++) {
bGPDstroke *gps = td->extra;
- gps->flag |= GP_STROKE_RECALC_CACHES;
+ if (gps != NULL) {
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ }
}
}
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 309ad22e31c..075f311db72 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -58,6 +58,7 @@
#include "BKE_pointcache.h"
#include "BKE_editmesh.h"
#include "BKE_lattice.h"
+#include "BKE_gpencil.h"
#include "BIF_gl.h"
@@ -68,6 +69,7 @@
#include "ED_curve.h"
#include "ED_particle.h"
#include "ED_view3d.h"
+#include "ED_gpencil.h"
#include "UI_resources.h"
@@ -288,24 +290,49 @@ static int calc_manipulator_stats(const bContext *C)
zero_v3(scene->twcent);
if (is_gp_edit) {
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- /* we're only interested in selected points here... */
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
-
- /* Change selection status of all points, then make the stroke match */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- calc_tw_center(scene, &pt->x);
- totsel++;
+ float diff_mat[4][4];
+ float fpt[3];
+
+ 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)) {
+
+ /* calculate difference matrix if parent object */
+ if (gpl->parent != NULL) {
+ ED_gpencil_parent_location(gpl, diff_mat);
+ }
+
+ 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;
+ }
+
+ /* we're only interested in selected points here... */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ /* Change selection status of all points, then make the stroke match */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (gpl->parent == NULL) {
+ calc_tw_center(scene, &pt->x);
+ totsel++;
+ }
+ else {
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ calc_tw_center(scene, fpt);
+ totsel++;
+ }
+ }
+ }
}
}
}
}
- CTX_DATA_END;
-
+
+
/* selection center */
if (totsel) {
mul_v3_fl(scene->twcent, 1.0f / (float)totsel); /* centroid! */
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 0bb64315845..f8bb124e943 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -984,15 +984,6 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
}
if (found == true) {
- float tangent[3];
-
- sub_v2_v2v2(tangent, loc, t->tsnap.snapPoint);
- tangent[2] = 0.0f;
-
- if (!is_zero_v3(tangent)) {
- copy_v3_v3(t->tsnap.snapTangent, tangent);
- }
-
copy_v3_v3(t->tsnap.snapPoint, loc);
copy_v3_v3(t->tsnap.snapNormal, no);
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index ea5a55731c3..1f5e2b63bfa 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -807,6 +807,7 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
// sets the id of the rep
rep->setId(Id(id, 0));
rep->setName(obi->ob->id.name + 2);
+ rep->setLibraryPath(obi->ob->id.lib ? obi->ob->id.lib->name : NULL);
const BBox<Vec3r> bbox = BBox<Vec3r>(Vec3r(ls.minBBox[0], ls.minBBox[1], ls.minBBox[2]),
Vec3r(ls.maxBBox[0], ls.maxBBox[1], ls.maxBBox[2]));
diff --git a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
index 253bf278478..f2f53159fcf 100644
--- a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
+++ b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
@@ -296,6 +296,19 @@ static PyObject *ViewShape_name_get(BPy_ViewShape *self, void *UNUSED(closure))
return PyUnicode_FromString(self->vs->getName());
}
+PyDoc_STRVAR(ViewShape_library_path_doc,
+"The library path of the ViewShape.\n"
+"\n"
+":type: str, or None if the ViewShape is not part of a library");
+
+static PyObject *ViewShape_library_path_get(BPy_ViewShape *self, void *UNUSED(closure))
+{
+ const char *name = self->vs->getLibraryPath();
+ if (!name)
+ Py_RETURN_NONE;
+ return PyUnicode_FromString(name);
+}
+
PyDoc_STRVAR(ViewShape_id_doc,
"The Id of this ViewShape.\n"
"\n"
@@ -313,6 +326,7 @@ static PyGetSetDef BPy_ViewShape_getseters[] = {
(char *)ViewShape_vertices_doc, NULL},
{(char *)"edges", (getter)ViewShape_edges_get, (setter)ViewShape_edges_set, (char *)ViewShape_edges_doc, NULL},
{(char *)"name", (getter)ViewShape_name_get, (setter)NULL, (char *)ViewShape_name_doc, NULL},
+ {(char *)"library_path", (getter)ViewShape_library_path_get, (setter)NULL, (char *)ViewShape_library_path_doc, NULL},
{(char *)"id", (getter)ViewShape_id_get, (setter)NULL, (char *)ViewShape_id_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/scene_graph/Rep.h b/source/blender/freestyle/intern/scene_graph/Rep.h
index c5036cdb153..773eb2d3278 100644
--- a/source/blender/freestyle/intern/scene_graph/Rep.h
+++ b/source/blender/freestyle/intern/scene_graph/Rep.h
@@ -48,6 +48,8 @@ public:
inline Rep() : BaseObject()
{
_Id = 0;
+ _Name = 0;
+ _LibraryPath = 0;
_FrsMaterial = 0;
}
@@ -55,6 +57,7 @@ public:
{
_Id = iBrother._Id;
_Name = iBrother._Name;
+ _LibraryPath = iBrother._LibraryPath;
if (0 == iBrother._FrsMaterial)
_FrsMaterial = 0;
else
@@ -68,6 +71,7 @@ public:
std::swap(_BBox, ioOther._BBox);
std::swap(_Id, ioOther._Id);
std::swap(_Name, ioOther._Name);
+ std::swap(_LibraryPath, ioOther._LibraryPath);
std::swap(_FrsMaterial, ioOther._FrsMaterial);
}
@@ -76,6 +80,7 @@ public:
if (&iBrother != this) {
_Id = iBrother._Id;
_Name = iBrother._Name;
+ _LibraryPath = iBrother._LibraryPath;
if (0 == iBrother._FrsMaterial) {
_FrsMaterial = 0;
}
@@ -132,6 +137,11 @@ public:
return _Name;
}
+ inline const char *getLibraryPath() const
+ {
+ return _LibraryPath;
+ }
+
inline const FrsMaterial *frs_material() const
{
return _FrsMaterial;
@@ -153,7 +163,12 @@ public:
_Name = name;
}
- inline void setFrsMaterial(const FrsMaterial& iMaterial)
+ inline void setLibraryPath(const char *path)
+ {
+ _LibraryPath = path;
+ }
+
+ inline void setFrsMaterial(const FrsMaterial& iMaterial)
{
_FrsMaterial = new FrsMaterial(iMaterial);
}
@@ -162,6 +177,7 @@ private:
BBox<Vec3f> _BBox;
Id _Id;
const char *_Name;
+ const char *_LibraryPath;
FrsMaterial *_FrsMaterial;
};
diff --git a/source/blender/freestyle/intern/view_map/BoxGrid.cpp b/source/blender/freestyle/intern/view_map/BoxGrid.cpp
index ae22a26ec9b..34fa2b14379 100644
--- a/source/blender/freestyle/intern/view_map/BoxGrid.cpp
+++ b/source/blender/freestyle/intern/view_map/BoxGrid.cpp
@@ -77,11 +77,11 @@ BoxGrid::Iterator::Iterator (BoxGrid& grid, Vec3r& center, real /*epsilon*/)
// Find target cell
_cell = grid.findCell(_target);
#if BOX_GRID_LOGGING
- if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "Searching for occluders of edge centered at " << _target << " in cell [" <<
- 1_cell->boundary[0] << ", " << _cell->boundary[1] << ", " << _cell->boundary[2] <<
- ", " << _cell->boundary[3] << "] (" << _cell->faces.size() << " occluders)" << endl;
- }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Searching for occluders of edge centered at " << _target << " in cell [" <<
+ 1_cell->boundary[0] << ", " << _cell->boundary[1] << ", " << _cell->boundary[2] <<
+ ", " << _cell->boundary[3] << "] (" << _cell->faces.size() << " occluders)" << endl;
+ }
#endif
// Set iterator
diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h
index b9924e6ad95..9d373107bfa 100644
--- a/source/blender/freestyle/intern/view_map/Silhouette.h
+++ b/source/blender/freestyle/intern/view_map/Silhouette.h
@@ -1416,6 +1416,7 @@ private:
vector<FEdge*> _edgesList; // list of all edges
Id _Id;
const char *_Name;
+ const char *_LibraryPath;
BBox<Vec3r> _BBox;
vector<FrsMaterial> _FrsMaterials;
@@ -1436,6 +1437,7 @@ public:
_importance = 0.0f;
_ViewShape = NULL;
_Name = NULL;
+ _LibraryPath = NULL;
}
/*! Copy constructor */
@@ -1444,6 +1446,7 @@ public:
userdata = NULL;
_Id = iBrother._Id;
_Name = iBrother._Name;
+ _LibraryPath = iBrother._LibraryPath;
_BBox = iBrother.bbox();
_FrsMaterials = iBrother._FrsMaterials;
_importance = iBrother._importance;
@@ -1893,6 +1896,12 @@ public:
return _Name;
}
+ /*! Returns the library path of the Shape. */
+ inline const char *getLibraryPath() const
+ {
+ return _LibraryPath;
+ }
+
/* Modififers */
/*! Sets the Id of the shape.*/
inline void setId(Id id)
@@ -1906,6 +1915,12 @@ public:
_Name = name;
}
+ /*! Sets the library path of the shape.*/
+ inline void setLibraryPath(const char *path)
+ {
+ _LibraryPath = path;
+ }
+
/*! Sets the list of materials for the shape */
inline void setFrsMaterials(const vector<FrsMaterial>& iMaterials)
{
diff --git a/source/blender/freestyle/intern/view_map/ViewMap.h b/source/blender/freestyle/intern/view_map/ViewMap.h
index 74297e1dbfd..8b73c8aac3a 100644
--- a/source/blender/freestyle/intern/view_map/ViewMap.h
+++ b/source/blender/freestyle/intern/view_map/ViewMap.h
@@ -1565,12 +1565,18 @@ public:
return _SShape->getId();
}
- /*! Returns the ViewShape id. */
+ /*! Returns the ViewShape name. */
inline const char *getName() const
{
return _SShape->getName();
}
+ /*! Returns the ViewShape library path. */
+ inline const char *getLibraryPath() const
+ {
+ return _SShape->getLibraryPath();
+ }
+
/* modifiers */
/*! Sets the SShape on top of which the ViewShape is built. */
inline void setSShape(SShape *iSShape)
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
index 9ca021475b2..77beb1d97d9 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
@@ -1204,6 +1204,7 @@ void ViewMapBuilder::computeInitialViewEdges(WingedEdge& we)
psShape = new SShape;
psShape->setId((*it)->GetId());
psShape->setName((*it)->getName());
+ psShape->setLibraryPath((*it)->getLibraryPath());
psShape->setFrsMaterials((*it)->frs_materials()); // FIXME
// create the view shape
diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.cpp b/source/blender/freestyle/intern/winged_edge/WEdge.cpp
index 99aa2d22239..7bec5ba1d6e 100644
--- a/source/blender/freestyle/intern/winged_edge/WEdge.cpp
+++ b/source/blender/freestyle/intern/winged_edge/WEdge.cpp
@@ -471,6 +471,7 @@ WShape::WShape(WShape& iBrother)
{
_Id = iBrother.GetId();
_Name = iBrother._Name;
+ _LibraryPath = iBrother._LibraryPath;
_FrsMaterials = iBrother._FrsMaterials;
#if 0
_meanEdgeSize = iBrother._meanEdgeSize;
diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.h b/source/blender/freestyle/intern/winged_edge/WEdge.h
index 8001342775b..14109fba843 100644
--- a/source/blender/freestyle/intern/winged_edge/WEdge.h
+++ b/source/blender/freestyle/intern/winged_edge/WEdge.h
@@ -1025,6 +1025,7 @@ protected:
vector<WFace *> _FaceList;
int _Id;
const char *_Name;
+ const char *_LibraryPath;
static unsigned _SceneCurrentId;
#if 0
Vec3f _min;
@@ -1043,6 +1044,8 @@ public:
#endif
_Id = _SceneCurrentId;
_SceneCurrentId++;
+ _Name = 0;
+ _LibraryPath = 0;
}
/*! copy constructor */
@@ -1127,6 +1130,11 @@ public:
return _Name;
}
+ inline const char *getLibraryPath() const
+ {
+ return _LibraryPath;
+ }
+
/*! modifiers */
static inline void setCurrentId(const unsigned id)
{
@@ -1176,6 +1184,11 @@ public:
_Name = name;
}
+ inline void setLibraryPath(const char *path)
+ {
+ _LibraryPath = path;
+ }
+
/*! designed to build a specialized WFace for use in MakeFace */
virtual WFace *instanciateFace() const
{
diff --git a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
index 78773a9680d..dfdeedef2e1 100644
--- a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
+++ b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
@@ -42,6 +42,7 @@ void WXEdgeBuilder::visitIndexedFaceSet(IndexedFaceSet& ifs)
}
shape->setId(ifs.getId().getFirst());
shape->setName(ifs.getName());
+ shape->setLibraryPath(ifs.getLibraryPath());
//ifs.setId(shape->GetId());
}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index aec94f9f2cb..c40bc8eaf27 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -1732,3 +1732,9 @@ void GPU_pass_free(GPUPass *pass)
MEM_freeN(pass->vertexcode);
MEM_freeN(pass);
}
+
+void GPU_pass_free_nodes(ListBase *nodes)
+{
+ gpu_nodes_free(nodes);
+}
+
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 417e46a83ee..7af17f9122d 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -183,6 +183,7 @@ void GPU_pass_update_uniforms(GPUPass *pass);
void GPU_pass_unbind(GPUPass *pass);
void GPU_pass_free(GPUPass *pass);
+void GPU_pass_free_nodes(ListBase *nodes);
void gpu_codegen_init(void);
void gpu_codegen_exit(void);
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 4775d2ed30a..ed9718f1a17 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -270,6 +270,9 @@ static int GPU_material_construct_end(GPUMaterial *material, const char *passnam
material->partangvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_ANG_VELOCITY));
return 1;
}
+ else {
+ GPU_pass_free_nodes(&material->nodes);
+ }
return 0;
}
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 827c52c9a5f..54f0003c086 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -55,7 +55,8 @@ struct GPUTexture {
int number; /* number for multitexture binding */
int refcount; /* reference count */
GLenum target; /* GL_TEXTURE_* */
- GLenum target_base; /* same as target, (but no multisample) */
+ GLenum target_base; /* same as target, (but no multisample)
+ * use it for unbinding */
GLuint bindcode; /* opengl identifier for texture */
int fromblender; /* we got the texture from Blender */
@@ -374,6 +375,9 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
GLint bindcode = GPU_verify_image(ima, iuser, textarget, 0, 0, mipmap, is_data);
GPU_update_image_time(ima, time);
+ /* see GPUInput::textarget: it can take two values - GL_TEXTURE_2D and GL_TEXTURE_CUBE_MAP
+ * these values are correct for glDisable, so textarget can be safely used in
+ * GPU_texture_bind/GPU_texture_unbind through tex->target_base */
if (textarget == GL_TEXTURE_2D)
gputt = TEXTARGET_TEXTURE_2D;
else
@@ -390,7 +394,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
tex->number = -1;
tex->refcount = 1;
tex->target = textarget;
- tex->target_base = GL_TEXTURE_2D;
+ tex->target_base = textarget;
tex->fromblender = 1;
ima->gputexture[gputt] = tex;
@@ -626,11 +630,11 @@ void GPU_texture_bind(GPUTexture *tex, int number)
GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number);
if (number != 0) glActiveTexture(arbnumber);
if (tex->bindcode != 0) {
- glBindTexture(tex->target, tex->bindcode);
+ glBindTexture(tex->target_base, tex->bindcode);
}
else
- GPU_invalid_tex_bind(tex->target);
- glEnable(tex->target);
+ GPU_invalid_tex_bind(tex->target_base);
+ glEnable(tex->target_base);
if (number != 0) glActiveTexture(GL_TEXTURE0);
tex->number = number;
@@ -652,8 +656,6 @@ void GPU_texture_unbind(GPUTexture *tex)
GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number);
if (tex->number != 0) glActiveTexture(arbnumber);
- glBindTexture(tex->target, 0);
- glDisable(tex->target);
glBindTexture(tex->target_base, 0);
glDisable(tex->target_base);
if (tex->number != 0) glActiveTexture(GL_TEXTURE0);
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index bb5d2b4cf29..5c1bfc229da 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -213,43 +213,50 @@ typedef struct PreviewImage {
* Written to #BHead.code (for file IO)
* and the first 2 bytes of #ID.name (for runtime checks, see #GS macro).
*/
-#define ID_SCE MAKE_ID2('S', 'C') /* Scene */
-#define ID_LI MAKE_ID2('L', 'I') /* Library */
-#define ID_OB MAKE_ID2('O', 'B') /* Object */
-#define ID_ME MAKE_ID2('M', 'E') /* Mesh */
-#define ID_CU MAKE_ID2('C', 'U') /* Curve */
-#define ID_MB MAKE_ID2('M', 'B') /* MetaBall */
-#define ID_MA MAKE_ID2('M', 'A') /* Material */
-#define ID_TE MAKE_ID2('T', 'E') /* Tex (Texture) */
-#define ID_IM MAKE_ID2('I', 'M') /* Image */
-#define ID_LT MAKE_ID2('L', 'T') /* Lattice */
-#define ID_LA MAKE_ID2('L', 'A') /* Lamp */
-#define ID_CA MAKE_ID2('C', 'A') /* Camera */
-#define ID_IP MAKE_ID2('I', 'P') /* Ipo (depreciated, replaced by FCurves) */
-#define ID_KE MAKE_ID2('K', 'E') /* Key (shape key) */
-#define ID_WO MAKE_ID2('W', 'O') /* World */
-#define ID_SCR MAKE_ID2('S', 'R') /* Screen */
-#define ID_SCRN MAKE_ID2('S', 'N') /* (depreciated?) */
-#define ID_VF MAKE_ID2('V', 'F') /* VFont (Vector Font) */
-#define ID_TXT MAKE_ID2('T', 'X') /* Text */
-#define ID_SPK MAKE_ID2('S', 'K') /* Speaker */
-#define ID_SO MAKE_ID2('S', 'O') /* Sound */
-#define ID_GR MAKE_ID2('G', 'R') /* Group */
-#define ID_ID MAKE_ID2('I', 'D') /* (internal use only) */
-#define ID_AR MAKE_ID2('A', 'R') /* bArmature */
-#define ID_AC MAKE_ID2('A', 'C') /* bAction */
-#define ID_NT MAKE_ID2('N', 'T') /* bNodeTree */
-#define ID_BR MAKE_ID2('B', 'R') /* Brush */
-#define ID_PA MAKE_ID2('P', 'A') /* ParticleSettings */
-#define ID_GD MAKE_ID2('G', 'D') /* bGPdata, (Grease Pencil) */
-#define ID_WM MAKE_ID2('W', 'M') /* WindowManager */
-#define ID_MC MAKE_ID2('M', 'C') /* MovieClip */
-#define ID_MSK MAKE_ID2('M', 'S') /* Mask */
-#define ID_LS MAKE_ID2('L', 'S') /* FreestyleLineStyle */
-#define ID_PAL MAKE_ID2('P', 'L') /* Palette */
-#define ID_PC MAKE_ID2('P', 'C') /* PaintCurve */
-
- /* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */
+typedef enum ID_Type {
+ ID_SCE = MAKE_ID2('S', 'C'), /* Scene */
+ ID_LI = MAKE_ID2('L', 'I'), /* Library */
+ ID_OB = MAKE_ID2('O', 'B'), /* Object */
+ ID_ME = MAKE_ID2('M', 'E'), /* Mesh */
+ ID_CU = MAKE_ID2('C', 'U'), /* Curve */
+ ID_MB = MAKE_ID2('M', 'B'), /* MetaBall */
+ ID_MA = MAKE_ID2('M', 'A'), /* Material */
+ ID_TE = MAKE_ID2('T', 'E'), /* Tex (Texture) */
+ ID_IM = MAKE_ID2('I', 'M'), /* Image */
+ ID_LT = MAKE_ID2('L', 'T'), /* Lattice */
+ ID_LA = MAKE_ID2('L', 'A'), /* Lamp */
+ ID_CA = MAKE_ID2('C', 'A'), /* Camera */
+ ID_IP = MAKE_ID2('I', 'P'), /* Ipo (depreciated, replaced by FCurves) */
+ ID_KE = MAKE_ID2('K', 'E'), /* Key (shape key) */
+ ID_WO = MAKE_ID2('W', 'O'), /* World */
+ ID_SCR = MAKE_ID2('S', 'R'), /* Screen */
+ ID_VF = MAKE_ID2('V', 'F'), /* VFont (Vector Font) */
+ ID_TXT = MAKE_ID2('T', 'X'), /* Text */
+ ID_SPK = MAKE_ID2('S', 'K'), /* Speaker */
+ ID_SO = MAKE_ID2('S', 'O'), /* Sound */
+ ID_GR = MAKE_ID2('G', 'R'), /* Group */
+ ID_AR = MAKE_ID2('A', 'R'), /* bArmature */
+ ID_AC = MAKE_ID2('A', 'C'), /* bAction */
+ ID_NT = MAKE_ID2('N', 'T'), /* bNodeTree */
+ ID_BR = MAKE_ID2('B', 'R'), /* Brush */
+ ID_PA = MAKE_ID2('P', 'A'), /* ParticleSettings */
+ ID_GD = MAKE_ID2('G', 'D'), /* bGPdata, (Grease Pencil) */
+ ID_WM = MAKE_ID2('W', 'M'), /* WindowManager */
+ ID_MC = MAKE_ID2('M', 'C'), /* MovieClip */
+ ID_MSK = MAKE_ID2('M', 'S'), /* Mask */
+ ID_LS = MAKE_ID2('L', 'S'), /* FreestyleLineStyle */
+ ID_PAL = MAKE_ID2('P', 'L'), /* Palette */
+ ID_PC = MAKE_ID2('P', 'C'), /* PaintCurve */
+ ID_CF = MAKE_ID2('C', 'F'), /* CacheFile */
+} ID_Type;
+
+/* Only used as 'placeholder' in .blend files for directly linked datablocks. */
+#define ID_ID MAKE_ID2('I', 'D') /* (internal use only) */
+
+/* Deprecated. */
+#define ID_SCRN MAKE_ID2('S', 'N')
+
+/* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */
#define ID_SEQ MAKE_ID2('S', 'Q')
/* constraint */
#define ID_CO MAKE_ID2('C', 'O')
@@ -371,6 +378,47 @@ enum {
FILTER_ID_VF = (1 << 25),
FILTER_ID_WO = (1 << 26),
FILTER_ID_PA = (1 << 27),
+ FILTER_ID_CF = (1 << 28),
+};
+
+/* IMPORTANT: this enum matches the order currently use in set_lisbasepointers,
+ * keep them in sync! */
+enum {
+ INDEX_ID_LI = 0,
+ INDEX_ID_IP,
+ INDEX_ID_AC,
+ INDEX_ID_KE,
+ INDEX_ID_GD,
+ INDEX_ID_NT,
+ INDEX_ID_IM,
+ INDEX_ID_TE,
+ INDEX_ID_MA,
+ INDEX_ID_VF,
+ INDEX_ID_AR,
+ INDEX_ID_CF,
+ INDEX_ID_ME,
+ INDEX_ID_CU,
+ INDEX_ID_MB,
+ INDEX_ID_LT,
+ INDEX_ID_LA,
+ INDEX_ID_CA,
+ INDEX_ID_TXT,
+ INDEX_ID_SO,
+ INDEX_ID_GR,
+ INDEX_ID_PAL,
+ INDEX_ID_PC,
+ INDEX_ID_BR,
+ INDEX_ID_PA,
+ INDEX_ID_SPK,
+ INDEX_ID_WO,
+ INDEX_ID_MC,
+ INDEX_ID_SCR,
+ INDEX_ID_OB,
+ INDEX_ID_LS,
+ INDEX_ID_SCE,
+ INDEX_ID_WM,
+ INDEX_ID_MSK,
+ INDEX_ID_NULL,
};
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 9a19606d6c8..f3df9090d41 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -694,7 +694,9 @@ typedef enum eAnimEdit_Context {
/* dopesheet (default) */
SACTCONT_DOPESHEET = 3,
/* mask */
- SACTCONT_MASK = 4
+ SACTCONT_MASK = 4,
+ /* cache file */
+ SACTCONT_CACHEFILE = 5,
} eAnimEdit_Context;
/* SpaceAction AutoSnap Settings (also used by other Animation Editors) */
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 6bd7b3a4999..31fe8fe563e 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -450,7 +450,9 @@ typedef enum eDriver_Flags {
/* the names are cached so they don't need have python unicode versions created each time */
DRIVER_FLAG_RENAMEVAR = (1<<4),
/* intermediate values of driver should be shown in the UI for debugging purposes */
- DRIVER_FLAG_SHOWDEBUG = (1<<5)
+ DRIVER_FLAG_SHOWDEBUG = (1<<5),
+ /* include 'self' in the drivers namespace. */
+ DRIVER_FLAG_USE_SELF = (1<<6),
} eDriver_Flags;
/* F-Curves -------------------------------------- */
diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h
new file mode 100644
index 00000000000..1cda0233aa8
--- /dev/null
+++ b/source/blender/makesdna/DNA_cachefile_types.h
@@ -0,0 +1,84 @@
+/*
+ * ***** 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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file DNA_cachefile_types.h
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_CACHEFILE_TYPES_H__
+#define __DNA_CACHEFILE_TYPES_H__
+
+#include "DNA_ID.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* CacheFile::flag */
+enum {
+ CACHEFILE_DS_EXPAND = (1 << 0),
+};
+
+/* CacheFile::draw_flag */
+enum {
+ CACHEFILE_KEYFRAME_DRAWN = (1 << 0),
+};
+
+typedef struct AlembicObjectPath {
+ struct AlembicObjectPath *next, *prev;
+
+ char path[1024]; /* 1024 = FILE_MAX, might use PATH_MAX in the future. */
+} AlembicObjectPath;
+
+typedef struct CacheFile {
+ ID id;
+ struct AnimData *adt;
+
+ struct AbcArchiveHandle *handle;
+
+ /* Paths of the objects inside of the Alembic archive referenced by this
+ * CacheFile. */
+ ListBase object_paths;
+
+ char filepath[1024]; /* 1024 = FILE_MAX */
+
+ char is_sequence;
+ char forward_axis;
+ char up_axis;
+ char override_frame;
+
+ float scale;
+ float frame; /* The frame/time to lookup in the cache file. */
+
+ short flag; /* Animation flag. */
+ short draw_flag;
+} CacheFile;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DNA_CACHEFILE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h
index d385e303a7c..ee147da8dae 100644
--- a/source/blender/makesdna/DNA_cloth_types.h
+++ b/source/blender/makesdna/DNA_cloth_types.h
@@ -63,6 +63,7 @@ typedef struct ClothSimSettings {
float max_sewing; /* max sewing force */
float avg_spring_len; /* used for normalized springs */
float timescale; /* parameter how fast cloth runs */
+ float time_scale; /* multiplies cloth speed */
float maxgoal; /* see SB */
float eff_force_scale;/* Scaling of effector forces (see softbody_calc_forces).*/
float eff_wind_scale; /* Scaling of effector wind (see softbody_calc_forces). */
@@ -98,6 +99,7 @@ typedef struct ClothSimSettings {
short presets; /* used for presets on GUI */
short reset;
+ char pad0[4];
struct EffectorWeights *effector_weights;
} ClothSimSettings;
diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h
index 1d88b01cf62..f7ee1ff3915 100644
--- a/source/blender/makesdna/DNA_color_types.h
+++ b/source/blender/makesdna/DNA_color_types.h
@@ -49,7 +49,8 @@ typedef struct CurveMapPoint {
/* curvepoint->flag */
enum {
CUMA_SELECT = 1,
- CUMA_VECTOR = 2
+ CUMA_HANDLE_VECTOR = 2,
+ CUMA_HANDLE_AUTO_ANIM = 4,
};
typedef struct CurveMap {
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 5fcd374b21f..fc4e7de73f5 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -458,6 +458,12 @@ typedef struct bObjectSolverConstraint {
struct Object *camera;
} bObjectSolverConstraint;
+/* Transform matrix cache constraint */
+typedef struct bTransformCacheConstraint {
+ struct CacheFile *cache_file;
+ char object_path[1024]; /* FILE_MAX */
+} bTransformCacheConstraint;
+
/* ------------------------------------------ */
/* bConstraint->type
@@ -494,6 +500,7 @@ typedef enum eBConstraint_Types {
CONSTRAINT_TYPE_FOLLOWTRACK = 26, /* Follow Track Constraint */
CONSTRAINT_TYPE_CAMERASOLVER = 27, /* Camera Solver Constraint */
CONSTRAINT_TYPE_OBJECTSOLVER = 28, /* Object Solver Constraint */
+ CONSTRAINT_TYPE_TRANSFORM_CACHE = 29, /* Transform Cache Constraint */
/* NOTE: no constraints are allowed to be added after this */
NUM_CONSTRAINT_TYPES
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 41f53f9f51c..f1546053c5c 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2008, Blender Foundation.
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -32,9 +32,10 @@
#include "DNA_listBase.h"
#include "DNA_ID.h"
+#include "DNA_brush_types.h"
struct AnimData;
-
+struct CurveMapping;
/* Grease-Pencil Annotations - 'Stroke Point'
* -> Coordinates may either be 2d or 3d depending on settings at the time
@@ -44,6 +45,7 @@ struct AnimData;
typedef struct bGPDspoint {
float x, y, z; /* co-ordinates of point (usually 2d, but can be 3d as well) */
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) */
} bGPDspoint;
@@ -65,24 +67,113 @@ typedef struct bGPDtriangle {
int v1, v2, v3; /* indices for tesselated triangle used for GP Fill */
} 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;
+
+/* color of palettes */
+typedef struct bGPDpalettecolor {
+ struct bGPDpalettecolor *next, *prev;
+ char info[64]; /* Color name. Must be unique. */
+ float color[4];
+ float fill[4]; /* color that should be used for drawing "fills" for strokes */
+ short flag; /* settings for palette color */
+ char pad[6]; /* padding for compiler alignment error */
+} bGPDpalettecolor;
+
+/* bGPDpalettecolor->flag */
+typedef enum eGPDpalettecolor_Flag {
+ /* color is active */
+ PC_COLOR_ACTIVE = (1 << 0),
+ /* don't display color */
+ PC_COLOR_HIDE = (1 << 1),
+ /* protected from further editing */
+ PC_COLOR_LOCKED = (1 << 2),
+ /* do onion skinning */
+ PC_COLOR_ONIONSKIN = (1 << 3),
+ /* "volumetric" strokes (i.e. GLU Quadric discs in 3D) */
+ PC_COLOR_VOLUMETRIC = (1 << 4),
+ /* Use High quality fill */
+ PC_COLOR_HQ_FILL = (1 << 5)
+} eGPDpalettecolor_Flag;
+
+/* palette of colors */
+typedef struct bGPDpalette {
+ struct bGPDpalette *next, *prev;
+
+ /* pointer to individual colours */
+ ListBase colors;
+ char info[64]; /* Palette name. Must be unique. */
+
+ short flag;
+ char pad[6]; /* padding for compiler alignment error */
+} bGPDpalette;
+
+/* bGPDpalette->flag */
+typedef enum eGPDpalette_Flag {
+ /* palette is active */
+ PL_PALETTE_ACTIVE = (1 << 0)
+} eGPDpalette_Flag;
+
/* Grease-Pencil Annotations - 'Stroke'
* -> A stroke represents a (simplified version) of the curve
* drawn by the user in one 'mousedown'->'mouseup' operation
*/
typedef struct bGPDstroke {
struct bGPDstroke *next, *prev;
+
bGPDspoint *points; /* array of data-points for stroke */
- void *pad; /* keep 4 pointers at the beginning, padding for 'inittime' is tricky 64/32bit */
- int totpoints; /* number of data-points in array */
-
- short thickness; /* thickness of stroke (currently not used) */
- short flag; /* various settings about this stroke */
-
bGPDtriangle *triangles;/* tesselated triangles for GP Fill */
+ int totpoints; /* number of data-points in array */
int tot_triangles; /* number of triangles in array */
- int pad1, *pad2;
+
+ short thickness; /* thickness of stroke */
+ 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];
} bGPDstroke;
/* bGPDstroke->flag */
@@ -97,6 +188,10 @@ 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),
/* only for use with stroke-buffer (while drawing eraser) */
GP_STROKE_ERASER = (1 << 15)
} eGPDstroke_Flag;
@@ -139,16 +234,18 @@ typedef struct bGPDlayer {
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 that should be used to draw all the strokes in this layer */
- float fill[4]; /* color that should be used for drawing "fills" for strokes */
+ 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]; /* 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. */
- 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 */
- short pad[4]; /* padding for compiler error */
+ 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;
+ float tintcolor[4]; /* Color used to tint layer, alpha value is used as factor */
+ float opacity; /* Opacity of the layer */
} bGPDlayer;
/* bGPDlayer->flag */
@@ -176,7 +273,9 @@ typedef enum eGPDlayer_Flag {
/* "volumetric" strokes (i.e. GLU Quadric discs in 3D) */
GP_LAYER_VOLUMETRIC = (1 << 10),
/* Use high quality fill (instead of buggy legacy OpenGL Fill) */
- GP_LAYER_HQ_FILL = (1 << 11)
+ GP_LAYER_HQ_FILL = (1 << 11),
+ /* Unlock color */
+ GP_LAYER_UNLOCK_COLOR = (1 << 12)
} eGPDlayer_Flag;
/* Grease-Pencil Annotations - 'DataBlock' */
@@ -187,7 +286,7 @@ typedef struct bGPdata {
/* saved 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
@@ -195,6 +294,13 @@ typedef struct bGPdata {
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 */
+ char pad[6]; /* padding for compiler alignment error */
+ short sflag; /* settings for palette color */
+
+ /* saved paletes and brushes */
+ ListBase palettes;
+ //ListBase brushes;
} bGPdata;
/* bGPdata->flag */
@@ -229,7 +335,9 @@ typedef enum eGPdata_Flag {
GP_DATA_STROKE_EDITMODE = (1 << 8),
/* Convenience/cache flag to make it easier to quickly toggle onion skinning on/off */
- GP_DATA_SHOW_ONIONSKINS = (1 << 9)
+ 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)
} eGPdata_Flag;
#endif /* __DNA_GPENCIL_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index bbc8edf4344..0424dc98a25 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -85,6 +85,7 @@ typedef enum ModifierType {
eModifierType_DataTransfer = 49,
eModifierType_NormalEdit = 50,
eModifierType_CorrectiveSmooth = 51,
+ eModifierType_MeshSequenceCache = 52,
NUM_MODIFIER_TYPES
} ModifierType;
@@ -1541,4 +1542,25 @@ enum {
MOD_NORMALEDIT_MIX_MUL = 3,
};
+typedef struct MeshSeqCacheModifierData {
+ ModifierData modifier;
+
+ struct CacheFile *cache_file;
+ char object_path[1024]; /* 1024 = FILE_MAX */
+
+ char read_flag;
+ char pad[7];
+} MeshSeqCacheModifierData;
+
+/* MeshSeqCacheModifierData.read_flag */
+enum {
+ MOD_MESHSEQ_READ_VERT = (1 << 0),
+ MOD_MESHSEQ_READ_POLY = (1 << 1),
+ MOD_MESHSEQ_READ_UV = (1 << 2),
+ MOD_MESHSEQ_READ_COLOR = (1 << 3),
+};
+
+#define MOD_MESHSEQ_READ_ALL \
+ (MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)
+
#endif /* __DNA_MODIFIER_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h
index cccee82cb51..59acefeffe4 100644
--- a/source/blender/makesdna/DNA_object_force.h
+++ b/source/blender/makesdna/DNA_object_force.h
@@ -339,6 +339,8 @@ typedef struct SoftBody {
struct PointCache *pointcache;
struct ListBase ptcaches;
+ struct Group *collision_group;
+
struct EffectorWeights *effector_weights;
/* reverse esimated obmatrix .. no need to store in blend file .. how ever who cares */
float lcom[3];
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index 8a734ae7d9e..7c866f939ce 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -160,6 +160,7 @@ typedef struct ParticleSettings {
struct SPHFluidSettings *fluid;
struct EffectorWeights *effector_weights;
+ struct Group *collision_group;
int flag, rt;
short type, from, distr, texact;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index c7578a19e0c..a4934cc1f24 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -62,6 +62,7 @@ struct AnimData;
struct Editing;
struct SceneStats;
struct bGPdata;
+struct bGPDbrush;
struct MovieClip;
struct ColorSpace;
@@ -1117,12 +1118,12 @@ typedef enum eGP_EditBrush_Types {
GP_EDITBRUSH_TYPE_SUBDIVIDE = 7,
GP_EDITBRUSH_TYPE_SIMPLIFY = 8,
GP_EDITBRUSH_TYPE_CLONE = 9,
-
+ GP_EDITBRUSH_TYPE_STRENGTH = 10,
+
/* !!! Update GP_EditBrush_Data brush[###]; below !!! */
TOT_GP_EDITBRUSH_TYPES
} eGP_EditBrush_Types;
-
/* Settings for a GPencil Stroke Sculpting Brush */
typedef struct GP_EditBrush_Data {
short size; /* radius of brush */
@@ -1148,17 +1149,26 @@ typedef enum eGP_EditBrush_Flag {
/* GPencil Stroke Sculpting Settings */
typedef struct GP_BrushEdit_Settings {
- GP_EditBrush_Data brush[10]; /* TOT_GP_EDITBRUSH_TYPES */
+ GP_EditBrush_Data brush[11]; /* TOT_GP_EDITBRUSH_TYPES */
void *paintcursor; /* runtime */
int brushtype; /* eGP_EditBrush_Types */
int flag; /* eGP_BrushEdit_SettingsFlag */
+ char pad[4];
+ float alpha; /* alpha factor for selection color */
} GP_BrushEdit_Settings;
/* GP_BrushEdit_Settings.flag */
typedef enum eGP_BrushEdit_SettingsFlag {
/* only affect selected points */
- GP_BRUSHEDIT_FLAG_SELECT_MASK = (1 << 0)
+ GP_BRUSHEDIT_FLAG_SELECT_MASK = (1 << 0),
+ /* apply brush to position */
+ GP_BRUSHEDIT_FLAG_APPLY_POSITION = (1 << 1),
+ /* apply brush to strength */
+ GP_BRUSHEDIT_FLAG_APPLY_STRENGTH = (1 << 2),
+ /* apply brush to thickness */
+ GP_BRUSHEDIT_FLAG_APPLY_THICKNESS = (1 << 3)
+
} eGP_BrushEdit_SettingsFlag;
/* *************************************************************** */
@@ -1378,6 +1388,9 @@ typedef struct ToolSettings {
/* Grease Pencil Sculpt */
struct GP_BrushEdit_Settings gp_sculpt;
+ /* Grease Pencil Drawing Brushes (bGPDbrush) */
+ ListBase gp_brushes;
+
/* Image Paint (8 byttse aligned please!) */
struct ImagePaintSettings imapaint;
@@ -2075,6 +2088,8 @@ typedef enum eGPencil_Flags {
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)
} eGPencil_Flags;
/* toolsettings->gpencil_src */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index fbeabb351ac..e208ef39719 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -218,11 +218,18 @@ typedef struct ScrArea {
char temp, pad;
struct SpaceType *type; /* callbacks for this space type */
-
- ListBase spacedata; /* SpaceLink */
- ListBase regionbase; /* ARegion */
- ListBase handlers; /* wmEventHandler */
-
+
+ /* A list of space links (editors) that were open in this area before. When
+ * changing the editor type, we try to reuse old editor data from this list.
+ * The first item is the active/visible one.
+ */
+ ListBase spacedata; /* SpaceLink */
+ /* NOTE: This region list is the one from the active/visible editor (first item in
+ * spacedata list). Use SpaceLink.regionbase if it's inactive (but only then)!
+ */
+ ListBase regionbase; /* ARegion */
+ ListBase handlers; /* wmEventHandler */
+
ListBase actionzones; /* AZone */
} ScrArea;
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 4ce0f369ebd..41188c2412f 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -738,6 +738,7 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_COLLADA = (1 << 13),
FILE_TYPE_OPERATOR = (1 << 14), /* from filter_glob operator property */
FILE_TYPE_APPLICATIONBUNDLE = (1 << 15),
+ FILE_TYPE_ALEMBIC = (1 << 16),
FILE_TYPE_DIR = (1 << 30), /* An FS directory (i.e. S_ISDIR on its path is true). */
FILE_TYPE_BLENDERLIB = (1 << 31),
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index b78299316e1..2cea8715a65 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -129,6 +129,7 @@ static const char *includefiles[] = {
"DNA_rigidbody_types.h",
"DNA_freestyle_types.h",
"DNA_linestyle_types.h",
+ "DNA_cachefile_types.h",
/* see comment above before editing! */
/* empty string to indicate end of includefiles */
@@ -1340,4 +1341,5 @@ int main(int argc, char **argv)
#include "DNA_rigidbody_types.h"
#include "DNA_freestyle_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_cachefile_types.h"
/* end of list */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index b50d0f85701..45b0225ac1f 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -95,6 +95,8 @@ extern StructRNA RNA_Brush;
extern StructRNA RNA_BrushTextureSlot;
extern StructRNA RNA_BuildModifier;
extern StructRNA RNA_MeshCacheModifier;
+extern StructRNA RNA_MeshSequenceCacheModifier;
+extern StructRNA RNA_CacheFile;
extern StructRNA RNA_Camera;
extern StructRNA RNA_CastModifier;
extern StructRNA RNA_ChildOfConstraint;
@@ -258,6 +260,9 @@ 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_GPencilStroke;
extern StructRNA RNA_GPencilStrokePoint;
extern StructRNA RNA_GPencilSculptSettings;
@@ -694,6 +699,11 @@ void RNA_main_pointer_create(struct Main *main, PointerRNA *r_ptr);
void RNA_id_pointer_create(struct ID *id, PointerRNA *r_ptr);
void RNA_pointer_create(struct ID *id, StructRNA *type, void *data, PointerRNA *r_ptr);
+bool RNA_path_resolved_create(
+ PointerRNA *ptr, struct PropertyRNA *prop,
+ const int prop_index,
+ PathResolvedRNA *r_anim_rna);
+
void RNA_blender_rna_pointer_create(PointerRNA *r_ptr);
void RNA_pointer_recast(PointerRNA *ptr, PointerRNA *r_ptr);
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 7ae3d552916..1c9b3593d17 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -198,6 +198,8 @@ extern EnumPropertyItem rna_enum_dt_mix_mode_items[];
extern EnumPropertyItem rna_enum_dt_layers_select_src_items[];
extern EnumPropertyItem rna_enum_dt_layers_select_dst_items[];
+extern EnumPropertyItem rna_enum_abc_compression_items[];
+
/* API calls */
int rna_node_tree_type_to_enum(struct bNodeTreeType *typeinfo);
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 1d5f46a1814..276531992f9 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -64,6 +64,16 @@ typedef struct PropertyPointerRNA {
struct PropertyRNA *prop;
} PropertyPointerRNA;
+/**
+ * Stored result of a RNA path lookup (as used by anim-system)
+ */
+typedef struct PathResolvedRNA {
+ struct PointerRNA ptr;
+ struct PropertyRNA *prop;
+ /* -1 for non-array access */
+ int prop_index;
+} PathResolvedRNA;
+
/* Property */
typedef enum PropertyType {
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 2dee1fe3504..1f14ee60cbc 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -39,6 +39,7 @@ set(DEFSRC
rna_blenvm.c
rna_boid.c
rna_brush.c
+ rna_cachefile.c
rna_camera.c
rna_cloth.c
rna_color.c
@@ -292,6 +293,13 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_ALEMBIC)
+ list(APPEND INC
+ ../../alembic
+ )
+ add_definitions(-DWITH_ALEMBIC)
+endif()
+
if(WITH_BULLET)
list(APPEND INC
../../../../intern/rigidbody
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index b2355206071..2d68c58281a 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3302,6 +3302,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_blenvm.c", NULL, RNA_def_blenvm},
{"rna_boid.c", NULL, RNA_def_boid},
{"rna_brush.c", NULL, RNA_def_brush},
+ {"rna_cachefile.c", NULL, RNA_def_cachefile},
{"rna_camera.c", "rna_camera_api.c", RNA_def_camera},
{"rna_cloth.c", NULL, RNA_def_cloth},
{"rna_color.c", NULL, RNA_def_color},
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index b6e9844d97a..fdb93ac1a18 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -52,6 +52,7 @@ EnumPropertyItem rna_enum_id_type_items[] = {
{ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armature", ""},
{ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brush", ""},
{ID_CA, "CAMERA", ICON_CAMERA_DATA, "Camera", ""},
+ {ID_CF, "CACHEFILE", ICON_FILE, "Cache File", ""},
{ID_CU, "CURVE", ICON_CURVE_DATA, "Curve", ""},
{ID_VF, "FONT", ICON_FONT_DATA, "Font", ""},
{ID_GD, "GREASEPENCIL", ICON_GREASEPENCIL, "Grease Pencil", ""},
@@ -64,10 +65,10 @@ EnumPropertyItem rna_enum_id_type_items[] = {
{ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""},
{ID_MSK, "MASK", ICON_MOD_MASK, "Mask", ""},
{ID_MA, "MATERIAL", ICON_MATERIAL_DATA, "Material", ""},
- {ID_MB, "META", ICON_META_DATA, "MetaBall", ""},
+ {ID_MB, "META", ICON_META_DATA, "Metaball", ""},
{ID_ME, "MESH", ICON_MESH_DATA, "Mesh", ""},
- {ID_MC, "MOVIECLIP", ICON_CLIP, "MovieClip", ""},
- {ID_NT, "NODETREE", ICON_NODETREE, "NodeTree", ""},
+ {ID_MC, "MOVIECLIP", ICON_CLIP, "Movie Clip", ""},
+ {ID_NT, "NODETREE", ICON_NODETREE, "Node Tree", ""},
{ID_OB, "OBJECT", ICON_OBJECT_DATA, "Object", ""},
{ID_PC, "PAINTCURVE", ICON_CURVE_BEZCURVE, "Paint Curve", ""},
{ID_PAL, "PALETTE", ICON_COLOR, "Palette", ""},
@@ -139,6 +140,7 @@ short RNA_type_to_ID_code(StructRNA *type)
if (RNA_struct_is_a(type, &RNA_Action)) return ID_AC;
if (RNA_struct_is_a(type, &RNA_Armature)) return ID_AR;
if (RNA_struct_is_a(type, &RNA_Brush)) return ID_BR;
+ if (RNA_struct_is_a(type, &RNA_CacheFile)) return ID_CF;
if (RNA_struct_is_a(type, &RNA_Camera)) return ID_CA;
if (RNA_struct_is_a(type, &RNA_Curve)) return ID_CU;
if (RNA_struct_is_a(type, &RNA_GreasePencil)) return ID_GD;
@@ -179,6 +181,7 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_AR: return &RNA_Armature;
case ID_BR: return &RNA_Brush;
case ID_CA: return &RNA_Camera;
+ case ID_CF: return &RNA_CacheFile;
case ID_CU: return &RNA_Curve;
case ID_GD: return &RNA_GreasePencil;
case ID_GR: return &RNA_Group;
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 5a93e18a7dd..047e5ea17ab 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -6966,3 +6966,22 @@ bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNAEqualsMode mode)
return equals;
}
+
+bool RNA_path_resolved_create(
+ PointerRNA *ptr, struct PropertyRNA *prop,
+ const int prop_index,
+ PathResolvedRNA *r_anim_rna)
+{
+ int array_len = RNA_property_array_length(ptr, prop);
+
+ if ((array_len == 0) || (prop_index < array_len)) {
+ r_anim_rna->ptr = *ptr;
+ r_anim_rna->prop = prop;
+ r_anim_rna->prop_index = array_len ? prop_index : -1;
+
+ return true;
+ }
+ else {
+ return false;
+ }
+}
diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c
new file mode 100644
index 00000000000..7249ebd5feb
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_cachefile.c
@@ -0,0 +1,169 @@
+/*
+ * ***** 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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "DNA_cachefile_types.h"
+#include "DNA_scene_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_cachefile.h"
+#include "BKE_depsgraph.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#ifdef WITH_ALEMBIC
+# include "../../../alembic/ABC_alembic.h"
+#endif
+
+static void rna_CacheFile_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->data;
+
+ DAG_id_tag_update(&cache_file->id, 0);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+
+ UNUSED_VARS(bmain, scene);
+}
+
+static void rna_CacheFile_update_handle(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ CacheFile *cache_file = ptr->data;
+
+ BKE_cachefile_reload(bmain, cache_file);
+
+ rna_CacheFile_update(bmain, scene, ptr);
+}
+
+static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->data;
+ rna_iterator_listbase_begin(iter, &cache_file->object_paths, NULL);
+}
+
+#else
+
+/* cachefile.object_paths */
+static void rna_def_alembic_object_path(BlenderRNA *brna)
+{
+ StructRNA *srna = RNA_def_struct(brna, "AlembicObjectPath", NULL);
+ RNA_def_struct_sdna(srna, "AlembicObjectPath");
+ RNA_def_struct_ui_text(srna, "Object Path", "Path of an object inside of an Alembic archive");
+ RNA_def_struct_ui_icon(srna, ICON_NONE);
+
+ PropertyRNA *prop = RNA_def_property(srna, "path", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Path", "Object path");
+ RNA_def_struct_name_property(srna, prop);
+}
+
+/* cachefile.object_paths */
+static void rna_def_cachefile_object_paths(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ RNA_def_property_srna(cprop, "AlembicObjectPaths");
+ StructRNA *srna = RNA_def_struct(brna, "AlembicObjectPaths", NULL);
+ RNA_def_struct_sdna(srna, "CacheFile");
+ RNA_def_struct_ui_text(srna, "Object Paths", "Collection of object paths");
+}
+
+static void rna_def_cachefile(BlenderRNA *brna)
+{
+ StructRNA *srna = RNA_def_struct(brna, "CacheFile", "ID");
+ RNA_def_struct_sdna(srna, "CacheFile");
+ RNA_def_struct_ui_text(srna, "CacheFile", "");
+ RNA_def_struct_ui_icon(srna, ICON_FILE);
+
+ PropertyRNA *prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_ui_text(prop, "File Path", "Path to external displacements file");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update_handle");
+
+ prop = RNA_def_property(srna, "is_sequence", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Sequence", "Whether the cache is separated in a series of files");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update");
+
+ /* ----------------- For Scene time ------------------- */
+
+ prop = RNA_def_property(srna, "override_frame", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Override Frame",
+ "Whether to use a custom frame for looking up data in the cache file,"
+ " instead of using the current scene frame");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update");
+
+ prop = RNA_def_property(srna, "frame", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "frame");
+ RNA_def_property_range(prop, -MAXFRAME, MAXFRAME);
+ RNA_def_property_ui_text(prop, "Frame", "The time to use for looking up the data in the cache file,"
+ " or to determine which file to use in a file sequence");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update");
+
+ /* ----------------- Axis Conversion ----------------- */
+
+ prop = RNA_def_property(srna, "forward_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "forward_axis");
+ RNA_def_property_enum_items(prop, rna_enum_object_axis_items);
+ RNA_def_property_ui_text(prop, "Forward", "");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update");
+
+ prop = RNA_def_property(srna, "up_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "up_axis");
+ RNA_def_property_enum_items(prop, rna_enum_object_axis_items);
+ RNA_def_property_ui_text(prop, "Up", "");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update");
+
+ prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "scale");
+ RNA_def_property_range(prop, 0.0001f, 1000.0f);
+ RNA_def_property_ui_text(prop, "Scale", "Value by which to enlarge or shrink the object with respect to the world's origin"
+ " (only applicable through a Transform Cache constraint)");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update");
+
+ /* object paths */
+ prop = RNA_def_property(srna, "object_paths", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "object_paths", NULL);
+ RNA_def_property_collection_funcs(prop, "rna_CacheFile_object_paths_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "AlembicObjectPath");
+ RNA_def_property_srna(prop, "AlembicObjectPaths");
+ RNA_def_property_ui_text(prop, "Object Paths", "Paths of the objects inside the Alembic archive");
+ rna_def_cachefile_object_paths(brna, prop);
+
+ rna_def_animdata_common(srna);
+}
+
+void RNA_def_cachefile(BlenderRNA *brna)
+{
+ rna_def_cachefile(brna);
+ rna_def_alembic_object_path(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index c91b6487653..781e44c9ed6 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -436,11 +436,19 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "quality", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "stepsPerFrame");
- RNA_def_property_range(prop, 1, 80);
+ RNA_def_property_range(prop, 1, INT_MAX);
+ RNA_def_property_ui_range(prop, 1, 80, 1, -1);
RNA_def_property_ui_text(prop, "Quality",
"Quality of the simulation in steps per frame (higher is better quality but slower)");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+ prop = RNA_def_property(srna, "time_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "time_scale");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 10, 3);
+ RNA_def_property_ui_text(prop, "Speed", "Cloth speed is multiplied by this value");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
prop = RNA_def_property(srna, "vertex_group_shrink", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_ClothSettings_shrink_vgroup_get", "rna_ClothSettings_shrink_vgroup_length",
"rna_ClothSettings_shrink_vgroup_set");
@@ -557,6 +565,12 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Rest Shape Key", "Shape key to use the rest spring lengths from");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+ prop = RNA_def_property(srna, "use_dynamic_mesh", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH);
+ RNA_def_property_ui_text(prop, "Dynamic Base Mesh", "Make simulation respect deformations in the base mesh");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
/* unused */
/* unused still */
@@ -656,7 +670,8 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "collision_quality", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "loop_count");
- RNA_def_property_range(prop, 1, 20);
+ RNA_def_property_range(prop, 1, SHRT_MAX);
+ RNA_def_property_ui_range(prop, 1, 20, 1, -1);
RNA_def_property_ui_text(prop, "Collision Quality",
"How many collision iterations should be done. (higher is better quality but slower)");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -681,7 +696,8 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "self_collision_quality", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "self_loop_count");
- RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_range(prop, 1, SHRT_MAX);
+ RNA_def_property_ui_range(prop, 1, 10, 1, -1);
RNA_def_property_ui_text(prop, "Self Collision Quality",
"How many self collision iterations should be done "
"(higher is better quality but slower)");
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 1910493b933..a66867ece03 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -690,7 +690,8 @@ static void rna_def_curvemappoint(BlenderRNA *brna)
PropertyRNA *prop;
static EnumPropertyItem prop_handle_type_items[] = {
{0, "AUTO", 0, "Auto Handle", ""},
- {CUMA_VECTOR, "VECTOR", 0, "Vector Handle", ""},
+ {CUMA_HANDLE_AUTO_ANIM, "AUTO_CLAMPED", 0, "Auto Clamped Handle", ""},
+ {CUMA_HANDLE_VECTOR, "VECTOR", 0, "Vector Handle", ""},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 98560bf3452..db3f76f3cfc 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -72,6 +72,8 @@ EnumPropertyItem rna_enum_constraint_type_items[] = {
"Compensate for scaling one axis by applying suitable scaling to the other two axes"},
{CONSTRAINT_TYPE_TRANSFORM, "TRANSFORM", ICON_CONSTRAINT_DATA, "Transformation",
"Use one transform property from target to control another (or same) property on owner"},
+ {CONSTRAINT_TYPE_TRANSFORM_CACHE, "TRANSFORM_CACHE", ICON_CONSTRAINT_DATA, "Transform Cache",
+ "Look up the transformation matrix from an external file"},
{0, "", 0, N_("Tracking"), ""},
{CONSTRAINT_TYPE_CLAMPTO, "CLAMP_TO", ICON_CONSTRAINT_DATA, "Clamp To",
"Restrict movements to lie along a curve by remapping location along curve's longest axis"},
@@ -214,6 +216,8 @@ static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr)
return &RNA_CameraSolverConstraint;
case CONSTRAINT_TYPE_OBJECTSOLVER:
return &RNA_ObjectSolverConstraint;
+ case CONSTRAINT_TYPE_TRANSFORM_CACHE:
+ return &RNA_TransformCacheConstraint;
default:
return &RNA_UnknownType;
}
@@ -2571,6 +2575,27 @@ static void rna_def_constraint_object_solver(BlenderRNA *brna)
"rna_Constraint_cameraObject_poll");
}
+static void rna_def_constraint_transform_cache(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "TransformCacheConstraint", "Constraint");
+ RNA_def_struct_ui_text(srna, "Transform Cache Constraint", "Look up transformation from an external file");
+ RNA_def_struct_sdna_from(srna, "bTransformCacheConstraint", "data");
+
+ prop = RNA_def_property(srna, "cache_file", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "cache_file");
+ RNA_def_property_struct_type(prop, "CacheFile");
+ RNA_def_property_ui_text(prop, "Cache File", "");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_Constraint_dependency_update");
+
+ prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object Path", "Path to the object in the Alembic archive used to lookup the transform matrix");
+ RNA_def_property_update(prop, 0, "rna_Constraint_update");
+}
+
/* base struct for constraints */
void RNA_def_constraint(BlenderRNA *brna)
{
@@ -2687,6 +2712,7 @@ void RNA_def_constraint(BlenderRNA *brna)
rna_def_constraint_follow_track(brna);
rna_def_constraint_camera_solver(brna);
rna_def_constraint_object_solver(brna);
+ rna_def_constraint_transform_cache(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 5fb581eb74a..c521e93d33e 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -1600,7 +1600,13 @@ static void rna_def_channeldriver(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", DRIVER_FLAG_SHOWDEBUG);
RNA_def_property_ui_text(prop, "Show Debug Info",
"Show intermediate values for the driver calculations to allow debugging of drivers");
-
+
+ prop = RNA_def_property(srna, "use_self", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", DRIVER_FLAG_USE_SELF);
+ RNA_def_property_ui_text(prop, "Use Self",
+ "Include a 'self' variable in the name-space, "
+ "so drivers can easily reference the data being modified (object, bone, etc...)");
+
/* State Info (for Debugging) */
prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", DRIVER_FLAG_INVALID);
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 52c04bec743..80f4d5d05b6 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -15,7 +15,7 @@
* 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): Blender Foundation (2009), Joshua Leung
+ * Contributor(s): Blender Foundation (2009), Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -41,6 +41,17 @@
#include "rna_internal.h"
#include "WM_types.h"
+#include "DNA_object_types.h"
+#include "ED_gpencil.h"
+
+/* parent type */
+static EnumPropertyItem parent_type_items[] = {
+ {PAROBJECT, "OBJECT", 0, "Object", "The layer is parented to an object"},
+ {PARSKEL, "ARMATURE", 0, "Armature", ""},
+ {PARBONE, "BONE", 0, "Bone", "The layer is parented to a bone"},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
@@ -49,8 +60,7 @@
#include "WM_api.h"
#include "BKE_gpencil.h"
-
-#include "DNA_object_types.h"
+#include "BKE_action.h"
static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
@@ -90,6 +100,16 @@ 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)
+{
+ bGPDstroke *gps = (bGPDstroke *)ptr->data;
+ gps->flag |= GP_STROKE_RECALC_COLOR;
+ gps->palcolor = NULL;
+
+ /* Now do standard updates... */
+ rna_GPencil_update(bmain, scene, ptr);
+}
+
static char *rna_GPencilLayer_path(PointerRNA *ptr)
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
@@ -123,38 +143,140 @@ static void rna_GPencilLayer_line_width_range(PointerRNA *ptr, int *min, int *ma
* 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 = 1;
+ *min = -300;
*max = 300;
- *softmin = 1;
+ *softmin = -100;
*softmax = 100;
}
else {
- *min = 1;
+ *min = -10;
*max = 10;
- *softmin = 1;
+ *softmin = -10;
*softmax = 10;
}
}
-static int rna_GPencilLayer_is_stroke_visible_get(PointerRNA *ptr)
+/* set parent */
+static void set_parent(bGPDlayer *gpl, Object *par, const int type, const char *substr)
+{
+ if (type == PAROBJECT) {
+ invert_m4_m4(gpl->inverse, par->obmat);
+ gpl->parent = par;
+ gpl->partype |= PAROBJECT;
+ gpl->parsubstr[0] = 0;
+ }
+ else if (type == PARSKEL) {
+ invert_m4_m4(gpl->inverse, par->obmat);
+ gpl->parent = par;
+ gpl->partype |= PARSKEL;
+ gpl->parsubstr[0] = 0;
+ }
+ else if (type == PARBONE) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(par->pose, substr);
+ if (pchan) {
+ float tmp_mat[4][4];
+ mul_m4_m4m4(tmp_mat, par->obmat, pchan->pose_mat);
+
+ invert_m4_m4(gpl->inverse, tmp_mat);
+ gpl->parent = par;
+ gpl->partype |= PARBONE;
+ BLI_strncpy(gpl->parsubstr, substr, sizeof(gpl->parsubstr));
+ }
+ }
+}
+
+/* set parent object and inverse matrix */
+static void rna_GPencilLayer_parent_set(PointerRNA *ptr, PointerRNA value)
{
- /* see drawgpencil.c -> gp_draw_data_layers() for more details
- * about this limit for showing/not showing
- */
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
- return (gpl->color[3] > GPENCIL_ALPHA_OPACITY_THRESH);
+ Object *par = (Object *)value.data;
+
+ if (par != NULL) {
+ 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;
+ }
}
-static int rna_GPencilLayer_is_fill_visible_get(PointerRNA *ptr)
+/* set parent type */
+static void rna_GPencilLayer_parent_type_set(PointerRNA *ptr, int value)
+{
+ bGPDlayer *gpl = (bGPDlayer *)ptr->data;
+ Object *par = gpl->parent;
+ gpl->partype = value;
+
+ if (par != NULL) {
+ set_parent(gpl, par, value, gpl->parsubstr);
+ }
+}
+
+/* set parent bone */
+static void rna_GPencilLayer_parent_bone_set(PointerRNA *ptr, const char *value)
+{
+ bGPDlayer *gpl = (bGPDlayer *)ptr->data;
+
+ Object *par = gpl->parent;
+ gpl->partype = PARBONE;
+
+ if (par != NULL) {
+ set_parent(gpl, par, gpl->partype, value);
+ }
+}
+
+
+/* parent types enum */
+static EnumPropertyItem *rna_Object_parent_type_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ bGPDlayer *gpl = (bGPDlayer *)ptr->data;
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+
+ RNA_enum_items_add_value(&item, &totitem, parent_type_items, PAROBJECT);
+
+ if (gpl->parent) {
+ Object *par = gpl->parent;
+
+ if (par->type == OB_ARMATURE) {
+ /* special hack: prevents this being overrided */
+ RNA_enum_items_add_value(&item, &totitem, &parent_type_items[1], PARSKEL);
+ RNA_enum_items_add_value(&item, &totitem, parent_type_items, PARBONE);
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static int rna_GPencilLayer_is_parented_get(PointerRNA *ptr)
{
- /* see drawgpencil.c -> gp_draw_data_layers() for more details
- * about this limit for showing/not showing
- */
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
- return (gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH);
+ return (gpl->parent != NULL);
}
static PointerRNA rna_GPencil_active_layer_get(PointerRNA *ptr)
@@ -201,7 +323,7 @@ static void rna_GPencil_active_layer_set(PointerRNA *ptr, PointerRNA value)
static int rna_GPencil_active_layer_index_get(PointerRNA *ptr)
{
bGPdata *gpd = (bGPdata *)ptr->id.data;
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
return BLI_findindex(&gpd->layers, gpl);
}
@@ -211,7 +333,7 @@ static void rna_GPencil_active_layer_index_set(PointerRNA *ptr, int value)
bGPdata *gpd = (bGPdata *)ptr->id.data;
bGPDlayer *gpl = BLI_findlink(&gpd->layers, value);
- gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_setactive(gpd, gpl);
}
static void rna_GPencil_active_layer_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
@@ -244,7 +366,7 @@ static void rna_GPencil_use_onion_skinning_set(PointerRNA *ptr, const int value)
/* set new value */
if (value) {
/* enable on active layer (it's the one that's most likely to be of interest right now) */
- gpl = gpencil_layer_getactive(gpd);
+ gpl = BKE_gpencil_layer_getactive(gpd);
if (gpl) {
gpl->flag |= GP_LAYER_ONIONSKIN;
}
@@ -313,7 +435,7 @@ static void rna_GPencil_stroke_point_select_set(PointerRNA *ptr, const int value
pt->flag &= ~GP_SPOINT_SELECT;
/* Check if the stroke should be selected or not... */
- gpencil_stroke_sync_selection(gps);
+ BKE_gpencil_stroke_sync_selection(gps);
}
}
@@ -357,10 +479,12 @@ static void rna_GPencil_stroke_point_pop(bGPDstroke *stroke, ReportList *reports
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
-static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame)
+static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame, const char *colorname)
{
bGPDstroke *stroke = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
-
+ strcpy(stroke->colorname, colorname);
+ stroke->palcolor = NULL;
+ stroke->flag |= GP_STROKE_RECALC_COLOR;
BLI_addtail(&frame->strokes, stroke);
return stroke;
@@ -410,7 +534,7 @@ static bGPDframe *rna_GPencil_frame_new(bGPDlayer *layer, ReportList *reports, i
return NULL;
}
- frame = gpencil_frame_addnew(layer, frame_number);
+ frame = BKE_gpencil_frame_addnew(layer, frame_number);
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
@@ -425,7 +549,7 @@ static void rna_GPencil_frame_remove(bGPDlayer *layer, ReportList *reports, Poin
return;
}
- gpencil_layer_delframe(layer, frame);
+ BKE_gpencil_layer_delframe(layer, frame);
RNA_POINTER_INVALIDATE(frame_ptr);
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
@@ -433,7 +557,7 @@ static void rna_GPencil_frame_remove(bGPDlayer *layer, ReportList *reports, Poin
static bGPDframe *rna_GPencil_frame_copy(bGPDlayer *layer, bGPDframe *src)
{
- bGPDframe *frame = gpencil_frame_duplicate(src);
+ bGPDframe *frame = BKE_gpencil_frame_duplicate(src);
while (BKE_gpencil_layer_find_frame(layer, frame->framenum)) {
frame->framenum++;
@@ -448,7 +572,7 @@ static bGPDframe *rna_GPencil_frame_copy(bGPDlayer *layer, bGPDframe *src)
static bGPDlayer *rna_GPencil_layer_new(bGPdata *gpd, const char *name, int setactive)
{
- bGPDlayer *gl = gpencil_layer_addnew(gpd, name, setactive != 0);
+ bGPDlayer *gl = BKE_gpencil_layer_addnew(gpd, name, setactive != 0);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -463,7 +587,7 @@ static void rna_GPencil_layer_remove(bGPdata *gpd, ReportList *reports, PointerR
return;
}
- gpencil_layer_delete(gpd, layer);
+ BKE_gpencil_layer_delete(gpd, layer);
RNA_POINTER_INVALIDATE(layer_ptr);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -471,25 +595,258 @@ static void rna_GPencil_layer_remove(bGPdata *gpd, ReportList *reports, PointerR
static void rna_GPencil_frame_clear(bGPDframe *frame)
{
- free_gpencil_strokes(frame);
+ BKE_gpencil_free_strokes(frame);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
static void rna_GPencil_layer_clear(bGPDlayer *layer)
{
- free_gpencil_frames(layer);
+ BKE_gpencil_free_frames(layer);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
static void rna_GPencil_clear(bGPdata *gpd)
{
- free_gpencil_layers(&gpd->layers);
+ BKE_gpencil_free_layers(&gpd->layers);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
+/* Palettes */
+static bGPDpalette *rna_GPencil_palette_new(bGPdata *gpd, const char *name, int 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;
+
+ /* 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));
+}
+
+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;
+
+ /* rename all strokes */
+ BKE_gpencil_palettecolor_changename(gpd, palcolor->info, value);
+
+ /* 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));
+}
+
+static void rna_GPencilStrokeColor_info_set(PointerRNA *ptr, const char *value)
+{
+ bGPDstroke *gps = ptr->data;
+
+ /* copy the new name into the name slot */
+ BLI_strncpy_utf8(gps->colorname, value, sizeof(gps->colorname));
+}
+
+
+static int rna_GPencilPaletteColor_is_stroke_visible_get(PointerRNA *ptr)
+{
+ bGPDpalettecolor *pcolor = (bGPDpalettecolor *)ptr->data;
+ return (pcolor->color[3] > GPENCIL_ALPHA_OPACITY_THRESH);
+}
+
+static int 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;
+}
+
#else
static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
@@ -513,6 +870,12 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Pressure", "Pressure of tablet at point when drawing it");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "strength");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ 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, "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");
@@ -542,6 +905,35 @@ static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_int(func, "index", -1, INT_MIN, INT_MAX, "Index", "point index", INT_MIN, INT_MAX);
}
+/* This information is read only and it can be used by add-ons */
+static void rna_def_gpencil_triangle(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ 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");
+
+ /* point v1 */
+ prop = RNA_def_property(srna, "v1", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "v1");
+ RNA_def_property_ui_text(prop, "v1", "First triangle vertice index");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ /* point v2 */
+ prop = RNA_def_property(srna, "v2", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "v2");
+ RNA_def_property_ui_text(prop, "v2", "Second triangle vertice index");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ /* point v3 */
+ prop = RNA_def_property(srna, "v3", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "v3");
+ RNA_def_property_ui_text(prop, "v3", "Third triangle vertice index");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+}
+
static void rna_def_gpencil_stroke(BlenderRNA *brna)
{
StructRNA *srna;
@@ -566,6 +958,19 @@ 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);
+ /* 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");
+
/* Settings */
prop = RNA_def_property(srna, "draw_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
@@ -578,6 +983,27 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_stroke_select_set");
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");
+
+ /* 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 stroke (in pixels)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
}
static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop)
@@ -594,6 +1020,7 @@ 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);
@@ -721,45 +1148,33 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
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", GP_LAYER_HQ_FILL);
- RNA_def_property_ui_text(prop, "High Quality Fill", "Fill strokes using high quality method to avoid glitches (slower fps during animation playback)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Stroke Drawing Color */
- 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");
-
- prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "color[3]");
+ 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");
- /* Fill Drawing Color */
- prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "fill");
+ /* Tint Color */
+ prop = RNA_def_property(srna, "tint_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "tintcolor");
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_ui_text(prop, "Tint Color", "Color for tinting stroke colors");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- prop = RNA_def_property(srna, "fill_alpha", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "fill[3]");
+ /* Tint factor */
+ prop = RNA_def_property(srna, "tint_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "tintcolor[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_ui_text(prop, "Tint Factor", "Factor of tinting color");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- /* Line Thickness */
- prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL);
+ /* 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 of strokes (in pixels)");
+ RNA_def_property_ui_text(prop, "Thickness", "Thickness change to apply current strokes (in pixels)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Onion-Skinning */
@@ -803,31 +1218,6 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
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");
- /* 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, "rna_GPencil_update");
-
- /* 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 "
- "(smoothing strength is halved on each successive round of smoothing)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* 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, "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);
@@ -847,6 +1237,15 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Frame Locked", "Lock current frame displayed by layer");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ /* Unlock colors */
+ prop = RNA_def_property(srna, "unlock_color", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_UNLOCK_COLOR);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_COLOR_OFF, 1);
+ RNA_def_property_ui_text(prop, "Unlock color", "Unprotect colors selected from further editing "
+ "and/or frame changes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+
/* expose as layers.active */
#if 0
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
@@ -873,18 +1272,42 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "X Ray", "Make the layer draw in front of objects");
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_GPencilLayer_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_GPencilLayer_is_fill_visible_get", NULL);
+ /* Parent object */
+ prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_GPencilLayer_parent_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_ui_text(prop, "Parent", "Parent Object");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* parent type */
+ prop = RNA_def_property(srna, "parent_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "partype");
+ RNA_def_property_enum_items(prop, parent_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_GPencilLayer_parent_type_set", "rna_Object_parent_type_itemf");
+ RNA_def_property_ui_text(prop, "Parent Type", "Type of parent relation");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* parent bone */
+ prop = RNA_def_property(srna, "parent_bone", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "parsubstr");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilLayer_parent_bone_set");
+ RNA_def_property_ui_text(prop, "Parent Bone", "Name of parent bone in case of a bone parenting relation");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* matrix */
+ prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_float_sdna(prop, NULL, "inverse");
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "MatrixInverse", "Parent inverse transformation matrix");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* read only parented flag */
+ prop = RNA_def_property(srna, "is_parented", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_GPencilLayer_is_parented_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");
-
+ RNA_def_property_ui_text(prop, "Is Parented", "True when the layer parent object is set");
+
/* Layers API */
func = RNA_def_function(srna, "clear", "rna_GPencil_layer_clear");
RNA_def_function_ui_description(func, "Remove all the grease pencil layer data");
@@ -933,6 +1356,207 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_ui_text(prop, "Active Layer Index", "Index of active grease pencil layer");
}
+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");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Name */
+ prop = RNA_def_property(srna, "info", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Info", "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_RESTRICT_VIEW_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, "Ghost", "Display the color in onion skinning");
+ 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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+
+ 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_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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_boolean(func, "set_active", 0, "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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+
+ 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)
{
StructRNA *srna;
@@ -951,6 +1575,13 @@ 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);
@@ -967,6 +1598,12 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
"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);
+ prop = RNA_def_property(srna, "show_stroke_direction", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_SHOW_DIRECTION);
+ RNA_def_property_ui_text(prop, "Show Direction", "Show stroke drawing direction with a bigger green dot (start) "
+ "and smaller red dot (end) points");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* API Functions */
func = RNA_def_function(srna, "clear", "rna_GPencil_clear");
RNA_def_function_ui_description(func, "Remove all the grease pencil data");
@@ -980,8 +1617,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_palette(brna);
+ rna_def_gpencil_palettecolor(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 58746ee82e7..7dc3dacb36f 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -134,6 +134,7 @@ void RNA_def_actuator(struct BlenderRNA *brna);
void RNA_def_blenvm(struct BlenderRNA *brna);
void RNA_def_boid(struct BlenderRNA *brna);
void RNA_def_brush(struct BlenderRNA *brna);
+void RNA_def_cachefile(struct BlenderRNA *brna);
void RNA_def_camera(struct BlenderRNA *brna);
void RNA_def_cloth(struct BlenderRNA *brna);
void RNA_def_color(struct BlenderRNA *brna);
@@ -334,6 +335,7 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop);
+void RNA_def_main_cachefiles(BlenderRNA *brna, PropertyRNA *cprop);
/* ID Properties */
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index e0538d1c05b..3392d0d9b3a 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -281,6 +281,12 @@ static void rna_Main_linestyle_begin(CollectionPropertyIterator *iter, PointerRN
rna_iterator_listbase_begin(iter, &bmain->linestyle, NULL);
}
+static void rna_Main_cachefiles_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Main *bmain = (Main *)ptr->data;
+ rna_iterator_listbase_begin(iter, &bmain->cachefiles, NULL);
+}
+
static void rna_Main_version_get(PointerRNA *ptr, int *value)
{
Main *bmain = (Main *)ptr->data;
@@ -354,6 +360,7 @@ void RNA_def_main(BlenderRNA *brna)
{"movieclips", "MovieClip", "rna_Main_movieclips_begin", "Movie Clips", "Movie Clip datablocks", RNA_def_main_movieclips},
{"masks", "Mask", "rna_Main_masks_begin", "Masks", "Masks datablocks", RNA_def_main_masks},
{"linestyles", "FreestyleLineStyle", "rna_Main_linestyle_begin", "Line Styles", "Line Style datablocks", RNA_def_main_linestyles},
+ {"cache_files", "CacheFile", "rna_Main_cachefiles_begin", "Cache Files", "Cache Files datablocks", RNA_def_main_cachefiles},
{NULL, NULL, NULL, NULL, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 0083207efd0..7c627e72fd5 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -535,6 +535,7 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(gpencil, gpencil, ID_GD)
RNA_MAIN_ID_TAG_FUNCS_DEF(movieclips, movieclip, ID_MC)
RNA_MAIN_ID_TAG_FUNCS_DEF(masks, mask, ID_MSK)
RNA_MAIN_ID_TAG_FUNCS_DEF(linestyle, linestyle, ID_LS)
+RNA_MAIN_ID_TAG_FUNCS_DEF(cachefiles, cachefiles, ID_CF)
#undef RNA_MAIN_ID_TAG_FUNCS_DEF
@@ -1548,6 +1549,21 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Main_palettes_is_updated_get", NULL);
}
+void RNA_def_main_cachefiles(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ RNA_def_property_srna(cprop, "BlendDataCacheFiles");
+ StructRNA *srna = RNA_def_struct(brna, "BlendDataCacheFiles", NULL);
+ RNA_def_struct_sdna(srna, "Main");
+ RNA_def_struct_ui_text(srna, "Main Cache Files", "Collection of cache files");
+
+ FunctionRNA *func = RNA_def_function(srna, "tag", "rna_Main_cachefiles_tag");
+ PropertyRNA *parm = RNA_def_boolean(func, "value", 0, "Value", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+
+ PropertyRNA *prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_Main_cachefiles_is_updated_get", NULL);
+}
void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -1564,7 +1580,7 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
- func = RNA_def_function(srna, "new", "gpencil_data_addnew");
+ func = RNA_def_function(srna, "new", "BKE_gpencil_data_addnew");
RNA_def_function_flag(func, FUNC_NO_SELF);
parm = RNA_def_string(func, "name", "GreasePencil", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index a23ef6eaa82..0b55c19c374 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include "DNA_armature_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -65,6 +66,7 @@ EnumPropertyItem rna_enum_object_modifier_type_items[] = {
{0, "", 0, N_("Modify"), ""},
{eModifierType_DataTransfer, "DATA_TRANSFER", ICON_MOD_DATA_TRANSFER, "Data Transfer", ""},
{eModifierType_MeshCache, "MESH_CACHE", ICON_MOD_MESHDEFORM, "Mesh Cache", ""},
+ {eModifierType_MeshSequenceCache, "MESH_SEQUENCE_CACHE", ICON_MOD_MESHDEFORM, "Mesh Sequence Cache", ""},
{eModifierType_NormalEdit, "NORMAL_EDIT", ICON_MOD_NORMALEDIT, "Normal Edit", ""},
{eModifierType_UVProject, "UV_PROJECT", ICON_MOD_UVPROJECT, "UV Project", ""},
{eModifierType_UVWarp, "UV_WARP", ICON_MOD_UVPROJECT, "UV Warp", ""},
@@ -281,6 +283,7 @@ EnumPropertyItem rna_enum_axis_flag_xyz_items[] = {
#include "DNA_curve_types.h"
#include "DNA_smoke_types.h"
+#include "BKE_cachefile.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_library.h"
@@ -288,6 +291,10 @@ EnumPropertyItem rna_enum_axis_flag_xyz_items[] = {
#include "BKE_object.h"
#include "BKE_particle.h"
+#ifdef WITH_ALEMBIC
+# include "ABC_alembic.h"
+#endif
+
static void rna_UVProject_projectors_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
UVProjectModifierData *uvp = (UVProjectModifierData *)ptr->data;
@@ -399,6 +406,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_NormalEditModifier;
case eModifierType_CorrectiveSmooth:
return &RNA_CorrectiveSmoothModifier;
+ case eModifierType_MeshSequenceCache:
+ return &RNA_MeshSequenceCacheModifier;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -4216,6 +4225,42 @@ static void rna_def_modifier_meshcache(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
+static void rna_def_modifier_meshseqcache(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "MeshSequenceCacheModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Cache Modifier", "Cache Mesh");
+ RNA_def_struct_sdna(srna, "MeshSeqCacheModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
+
+ prop = RNA_def_property(srna, "cache_file", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "cache_file");
+ RNA_def_property_struct_type(prop, "CacheFile");
+ RNA_def_property_ui_text(prop, "Cache File", "");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object Path", "Path to the object in the Alembic archive used to lookup geometric data");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ static EnumPropertyItem read_flag_items[] = {
+ {MOD_MESHSEQ_READ_VERT, "VERT", 0, "Vertex", ""},
+ {MOD_MESHSEQ_READ_POLY, "POLY", 0, "Faces", ""},
+ {MOD_MESHSEQ_READ_UV, "UV", 0, "UV", ""},
+ {MOD_MESHSEQ_READ_COLOR, "COLOR", 0, "Color", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ prop = RNA_def_property(srna, "read_data", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_enum_sdna(prop, NULL, "read_flag");
+ RNA_def_property_enum_items(prop, read_flag_items);
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+}
+
static void rna_def_modifier_laplaciandeform(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4745,6 +4790,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_wireframe(brna);
rna_def_modifier_datatransfer(brna);
rna_def_modifier_normaledit(brna);
+ rna_def_modifier_meshseqcache(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 33148549c45..3b91ddad969 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -2690,6 +2690,10 @@ static void rna_Node_image_layer_update(Main *bmain, Scene *scene, PointerRNA *p
BKE_image_signal(ima, iuser, IMA_SIGNAL_SRC_CHANGE);
rna_Node_update(bmain, scene, ptr);
+
+ if (scene->nodetree != NULL) {
+ ntreeCompositForceHidden(scene->nodetree);
+ }
}
static EnumPropertyItem *renderresult_layers_add_enum(RenderLayer *rl)
@@ -2823,6 +2827,14 @@ static EnumPropertyItem *rna_Node_scene_layer_itemf(bContext *UNUSED(C), Pointer
return item;
}
+static void rna_Node_scene_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ rna_Node_update(bmain, scene, ptr);
+ if (scene->nodetree != NULL) {
+ ntreeCompositForceHidden(scene->nodetree);
+ }
+}
+
static EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C), PointerRNA *ptr,
PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -4868,7 +4880,7 @@ static void def_cmp_render_layers(StructRNA *srna)
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Node_scene_layer_itemf");
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
RNA_def_property_ui_text(prop, "Layer", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_scene_layer_update");
}
static void rna_def_cmp_output_file_slot_file(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index a8d8407fe74..f05813043ca 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -1852,6 +1852,11 @@ static void rna_def_softbody(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Self Collision", "Enable naive vertex ball self collision");
RNA_def_property_update(prop, 0, "rna_softbody_update");
+ prop = RNA_def_property(srna, "collision_group", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Collision Group", "Limit colliders to this Group");
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "effector_weights");
RNA_def_property_struct_type(prop, "EffectorWeights");
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index a52473b95f2..eabf41cb332 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -2741,6 +2741,10 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Random Size", "Give the particle size a random variation");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
+ prop = RNA_def_property(srna, "collision_group", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Collision Group", "Limit colliders to this Group");
+ RNA_def_property_update(prop, 0, "rna_Particle_reset");
/* global physical properties */
prop = RNA_def_property(srna, "drag_factor", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index ed90f146f4d..156c327f97c 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -35,6 +35,7 @@
#include "DNA_linestyle_types.h"
#include "DNA_userdef_types.h"
#include "DNA_world_types.h"
+#include "DNA_gpencil_types.h"
#include "IMB_imbuf_types.h"
@@ -437,6 +438,7 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
#include "BKE_sequencer.h"
#include "BKE_animsys.h"
#include "BKE_freestyle.h"
+#include "BKE_gpencil.h"
#include "ED_info.h"
#include "ED_node.h"
@@ -449,6 +451,108 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
#include "FRS_freestyle.h"
#endif
+/* Grease pencil Drawing Brushes */
+static bGPDbrush *rna_GPencil_brush_new(ToolSettings *ts, const char *name, int 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_SpaceImageEditor_uv_sculpt_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
{
ED_space_image_uv_sculpt_update(bmain->wm.first, scene);
@@ -1991,6 +2095,203 @@ static int rna_gpu_is_hq_supported_get(PointerRNA *UNUSED(ptr))
#else
+/* 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, 0.0f, M_PI_2);
+ RNA_def_property_ui_text(prop, "Angle", "Angle of drawing when brush has full size");
+ 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", "Factor to apply when the brush rotate of its full size");
+ 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 "
+ "[+ reason/effect of using higher values of this property]");
+ 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_property_flag(parm, PROP_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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+
+ 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;
@@ -2311,6 +2612,12 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"are included as the basis for the new one");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "use_gpencil_draw_onback", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_PAINT_ONBACK);
+ RNA_def_property_ui_text(prop, "Draw Strokes on Back",
+ "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);
@@ -2322,7 +2629,14 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt");
RNA_def_property_struct_type(prop, "GPencilSculptSettings");
RNA_def_property_ui_text(prop, "Grease Pencil Sculpt", "");
-
+
+ /* 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");
@@ -6839,6 +7153,7 @@ 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_unified_paint_settings(brna);
rna_def_curve_paint_settings(brna);
rna_def_statvis(brna);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 1d3537dc9a0..ed51f0cffb0 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -37,6 +37,7 @@
#include "BLI_path_util.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "DNA_anim_types.h"
#include "DNA_object_types.h"
@@ -44,6 +45,18 @@
#include "rna_internal.h" /* own include */
+#ifdef WITH_ALEMBIC
+# include "../../alembic/ABC_alembic.h"
+#endif
+
+EnumPropertyItem rna_enum_abc_compression_items[] = {
+#ifdef WITH_ALEMBIC
+ { ABC_ARCHIVE_OGAWA, "OGAWA", 0, "Ogawa", "" },
+ { ABC_ARCHIVE_HDF5, "HDF5", 0, "HDF5", "" },
+#endif
+ { 0, NULL, 0, NULL, NULL }
+};
+
#ifdef RNA_RUNTIME
#include "BKE_animsys.h"
@@ -173,6 +186,73 @@ static void rna_Scene_ray_cast(
}
}
+#ifdef WITH_ALEMBIC
+
+static void rna_Scene_alembic_export(
+ Scene *scene,
+ bContext *C,
+ const char *filepath,
+ int frame_start,
+ int frame_end,
+ int xform_samples,
+ int geom_samples,
+ float shutter_open,
+ float shutter_close,
+ int selected_only,
+ int uvs,
+ int normals,
+ int vcolors,
+ int apply_subdiv,
+ int flatten_hierarchy,
+ int visible_layers_only,
+ int renderable_only,
+ int face_sets,
+ int use_subdiv_schema,
+ int compression_type,
+ int packuv,
+ float scale)
+{
+/* We have to enable allow_threads, because we may change scene frame number
+ * during export. */
+#ifdef WITH_PYTHON
+ BPy_BEGIN_ALLOW_THREADS;
+#endif
+
+ const struct AlembicExportParams params = {
+ .frame_start = frame_start,
+ .frame_end = frame_end,
+
+ .frame_step_xform = 1.0 / (double)xform_samples,
+ .frame_step_shape = 1.0 / (double)geom_samples,
+
+ .shutter_open = shutter_open,
+ .shutter_close = shutter_close,
+
+ .selected_only = selected_only,
+ .uvs = uvs,
+ .normals = normals,
+ .vcolors = vcolors,
+ .apply_subdiv = apply_subdiv,
+ .flatten_hierarchy = flatten_hierarchy,
+ .visible_layers_only = visible_layers_only,
+ .renderable_only = renderable_only,
+ .face_sets = face_sets,
+ .use_subdiv_schema = use_subdiv_schema,
+ .compression_type = compression_type,
+ .packuv = packuv,
+
+ .global_scale = scale,
+ };
+
+ ABC_export(scene, C, filepath, &params);
+
+#ifdef WITH_PYTHON
+ BPy_END_ALLOW_THREADS;
+#endif
+}
+
+#endif
+
#ifdef WITH_COLLADA
/* don't remove this, as COLLADA exporting cannot be done through operators in render() callback. */
#include "../../collada/collada.h"
@@ -296,6 +376,37 @@ void RNA_api_scene(StructRNA *srna)
RNA_def_function_ui_description(func, "Export to collada file");
#endif
+
+#ifdef WITH_ALEMBIC
+ func = RNA_def_function(srna, "alembic_export", "rna_Scene_alembic_export");
+ RNA_def_function_ui_description(func, "Export to Alembic file");
+
+ parm = RNA_def_string(func, "filepath", NULL, FILE_MAX, "File Path", "File path to write Alembic file");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_property_subtype(parm, PROP_FILEPATH); /* allow non utf8 */
+
+ RNA_def_int(func, "frame_start", 1, INT_MIN, INT_MAX, "Start", "Start Frame", INT_MIN, INT_MAX);
+ RNA_def_int(func, "frame_end", 1, INT_MIN, INT_MAX, "End", "End Frame", INT_MIN, INT_MAX);
+ RNA_def_int(func, "xform_samples", 1, 1, 128, "Xform samples", "Transform samples per frame", 1, 128);
+ RNA_def_int(func, "geom_samples", 1, 1, 128, "Geom samples", "Geometry samples per frame", 1, 128);
+ RNA_def_float(func, "shutter_open", 0.0f, -1.0f, 1.0f, "Shutter open", "", -1.0f, 1.0f);
+ RNA_def_float(func, "shutter_close", 1.0f, -1.0f, 1.0f, "Shutter close", "", -1.0f, 1.0f);
+ RNA_def_boolean(func, "selected_only" , 0, "Selected only", "Export only selected objects");
+ RNA_def_boolean(func, "uvs" , 1, "UVs", "Export UVs");
+ RNA_def_boolean(func, "normals" , 1, "Normals", "Export cormals");
+ RNA_def_boolean(func, "vcolors" , 0, "Vertex colors", "Export vertex colors");
+ RNA_def_boolean(func, "apply_subdiv" , 1, "Subsurfs as meshes", "Export subdivision surfaces as meshes");
+ RNA_def_boolean(func, "flatten" , 0, "Flatten hierarchy", "Flatten hierarchy");
+ RNA_def_boolean(func, "visible_layers_only" , 0, "Visible layers only", "Export only objects in visible layers");
+ RNA_def_boolean(func, "renderable_only" , 0, "Renderable objects only", "Export only objects marked renderable in the outliner");
+ RNA_def_boolean(func, "face_sets" , 0, "Facesets", "Export face sets");
+ RNA_def_boolean(func, "subdiv_schema", 0, "Use Alembic subdivision Schema", "Use Alembic subdivision Schema");
+ RNA_def_enum(func, "compression_type", rna_enum_abc_compression_items, 0, "Compression", "");
+ RNA_def_boolean(func, "packuv" , 0, "Export with packed UV islands", "Export with packed UV islands");
+ RNA_def_float(func, "scale", 1.0f, 0.0001f, 1000.0f, "Scale", "Value by which to enlarge or shrink the objects with respect to the world's origin", 0.0001f, 1000.0f);
+
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+#endif
}
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 90215bc883f..acde2e0957e 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -63,7 +63,8 @@ static EnumPropertyItem particle_edit_hair_brush_items[] = {
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_GRAB, "GRAB", 0, "Grab", "Translate the set of points initially within the brush circle"},
+ { 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"},
@@ -71,7 +72,7 @@ EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = {
//{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"},
- {0, NULL, 0, NULL, NULL}
+ { 0, NULL, 0, NULL, NULL }
};
EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
@@ -100,6 +101,11 @@ EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
#include "ED_particle.h"
+static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+}
+
static EnumPropertyItem particle_edit_disconnected_hair_brush_items[] = {
{PE_BRUSH_NONE, "NONE", 0, "None", "Don't use any brush"},
{PE_BRUSH_COMB, "COMB", 0, "Comb", "Comb hairs"},
@@ -1016,6 +1022,27 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_VERTEXSEL, 0); // FIXME: this needs a custom icon
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_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_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_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");
+
/* brush */
srna = RNA_def_struct(brna, "GPencilSculptBrush", NULL);
RNA_def_struct_sdna(srna, "GP_EditBrush_Data");
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index 9a31952b84b..dad5577dc12 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -76,6 +76,21 @@ static void rna_Smoke_resetCache(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
}
+static void rna_Smoke_cachetype_set(struct PointerRNA *ptr, int value)
+{
+ SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
+ Object *ob = (Object *)ptr->id.data;
+
+ if (value != settings->cache_file_format) {
+ /* Clear old caches. */
+ PTCacheID id;
+ BKE_ptcache_id_from_smoke(&id, ob, settings->smd);
+ BKE_ptcache_id_clear(&id, PTCACHE_CLEAR_ALL, 0);
+
+ settings->cache_file_format = value;
+ }
+}
+
static void rna_Smoke_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
{
SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
@@ -701,6 +716,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "cache_file_format", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "cache_file_format");
RNA_def_property_enum_items(prop, cache_file_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_Smoke_cachetype_set", NULL);
RNA_def_property_ui_text(prop, "File Format", "Select the file format to be used for caching");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
}
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 4818fe0cd35..1c8d4a4c818 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -3355,6 +3355,7 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
{SACTCONT_SHAPEKEY, "SHAPEKEY", ICON_SHAPEKEY_DATA, "Shape Key Editor", "Edit keyframes in active object's Shape Keys action"},
{SACTCONT_GPENCIL, "GPENCIL", ICON_GREASEPENCIL, "Grease Pencil", "Edit timings for all Grease Pencil sketches in file"},
{SACTCONT_MASK, "MASK", ICON_MOD_MASK, "Mask", "Edit timings for Mask Editor splines"},
+ {SACTCONT_CACHEFILE, "CACHEFILE", ICON_FILE, "Cache File", "Edit timings for Cache File data-blocks"},
{0, NULL, 0, NULL, NULL}
};
@@ -3799,6 +3800,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
{FILTER_ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armatures", "Show/hide Armature data-blocks"},
{FILTER_ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brushes", "Show/hide Brushes data-blocks"},
{FILTER_ID_CA, "CAMERA", ICON_CAMERA_DATA, "Cameras", "Show/hide Camera data-blocks"},
+ {FILTER_ID_CF, "CACHEFILE", ICON_FILE, "Cache Files", "Show/hide Cache File data-blocks"},
{FILTER_ID_CU, "CURVE", ICON_CURVE_DATA, "Curves", "Show/hide Curve data-blocks"},
{FILTER_ID_GD, "GREASE_PENCIL", ICON_GREASEPENCIL, "Grease Pencil", "Show/hide Grease pencil data-blocks"},
{FILTER_ID_GR, "GROUP", ICON_GROUP, "Groups", "Show/hide Group data-blocks"},
@@ -3844,7 +3846,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
"IMAGE", ICON_IMAGE_DATA, "Images & Sounds", "Show/hide images, movie clips, sounds and masks"},
{FILTER_ID_CA | FILTER_ID_LA | FILTER_ID_SPK | FILTER_ID_WO,
"ENVIRONMENT", ICON_WORLD_DATA, "Environment", "Show/hide worlds, lamps, cameras and speakers"},
- {FILTER_ID_BR | FILTER_ID_GD | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_TXT | FILTER_ID_VF,
+ {FILTER_ID_BR | FILTER_ID_GD | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_CF,
"MISC", ICON_GREASEPENCIL, "Miscellaneous", "Show/hide other data types"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 80777f57811..a751c414d83 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -912,6 +912,11 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_ui_description(func, "Node Socket Icon");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_float_array(func, "color", 4, node_socket_color_default, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f);
+
+ func = RNA_def_function(srna, "template_cache_file", "uiTemplateCacheFile");
+ RNA_def_function_ui_description(func, "Item(s). User interface for selecting cache files and their source paths");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
}
#endif
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 5c17ab46a78..96257f36de2 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -74,6 +74,7 @@ set(SRC
intern/MOD_meshcache_pc2.c
intern/MOD_meshcache_util.c
intern/MOD_meshdeform.c
+ intern/MOD_meshsequencecache.c
intern/MOD_mirror.c
intern/MOD_multires.c
intern/MOD_none.c
@@ -113,6 +114,13 @@ set(SRC
intern/MOD_weightvg_util.h
)
+if(WITH_ALEMBIC)
+ add_definitions(-DWITH_ALEMBIC)
+ list(APPEND INC
+ ../alembic
+ )
+endif()
+
if(WITH_MOD_BOOLEAN)
add_definitions(-DWITH_MOD_BOOLEAN)
list(APPEND SRC
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index a5d96759952..4c881445893 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -84,6 +84,7 @@ extern ModifierTypeInfo modifierType_Wireframe;
extern ModifierTypeInfo modifierType_DataTransfer;
extern ModifierTypeInfo modifierType_NormalEdit;
extern ModifierTypeInfo modifierType_CorrectiveSmooth;
+extern ModifierTypeInfo modifierType_MeshSequenceCache;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c
index 77fbb482f8b..ffbbb1b0745 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c
@@ -525,7 +525,7 @@ DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Scene *scene,
return dm;
/* sanity check */
- if (!fluidmd || (fluidmd && !fluidmd->fss))
+ if (!fluidmd || !fluidmd->fss)
return dm;
fss = fluidmd->fss;
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
new file mode 100644
index 00000000000..5a6a7904af5
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -0,0 +1,197 @@
+/*
+ * ***** 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): Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/modifiers/intern/MOD_meshsequencecache.c
+ * \ingroup modifiers
+ */
+
+#include "DNA_cachefile_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_cachefile.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_scene.h"
+
+#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
+#include "MOD_modifiertypes.h"
+
+#ifdef WITH_ALEMBIC
+# include "ABC_alembic.h"
+#endif
+
+static void initData(ModifierData *md)
+{
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+
+ mcmd->cache_file = NULL;
+ mcmd->object_path[0] = '\0';
+ mcmd->read_flag = MOD_MESHSEQ_READ_ALL;
+}
+
+static void copyData(ModifierData *md, ModifierData *target)
+{
+#if 0
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+#endif
+ MeshSeqCacheModifierData *tmcmd = (MeshSeqCacheModifierData *)target;
+
+ modifier_copyData_generic(md, target);
+
+ if (tmcmd->cache_file) {
+ id_us_plus(&tmcmd->cache_file->id);
+ }
+}
+
+static void freeData(ModifierData *md)
+{
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
+
+ if (mcmd->cache_file) {
+ id_us_min(&mcmd->cache_file->id);
+ }
+}
+
+static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+{
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
+
+ /* leave it up to the modifier to check the file is valid on calculation */
+ return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0');
+}
+
+static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
+ DerivedMesh *dm,
+ ModifierApplyFlag flag)
+{
+#ifdef WITH_ALEMBIC
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
+
+ Scene *scene = md->scene;
+ const float frame = BKE_scene_frame_get(scene);
+ const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS);
+
+ const char *err_str = NULL;
+
+ CacheFile *cache_file = mcmd->cache_file;
+
+ BKE_cachefile_ensure_handle(G.main, cache_file);
+
+ DerivedMesh *result = ABC_read_mesh(cache_file->handle,
+ ob,
+ dm,
+ mcmd->object_path,
+ time,
+ &err_str,
+ mcmd->read_flag);
+
+ if (err_str) {
+ modifier_setError(md, "%s", err_str);
+ }
+
+ return result ? result : dm;
+ UNUSED_VARS(flag);
+#else
+ return dm;
+ UNUSED_VARS(md, ob, flag);
+#endif
+}
+
+static bool dependsOnTime(ModifierData *md)
+{
+ UNUSED_VARS(md);
+ return true;
+}
+
+static void foreachIDLink(ModifierData *md, Object *ob,
+ IDWalkFunc walk, void *userData)
+{
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
+
+ walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_USER);
+}
+
+
+static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *bmain,
+ struct Scene *scene,
+ Object *ob, DagNode *obNode)
+{
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
+
+ if (mcmd->cache_file != NULL) {
+ DagNode *curNode = dag_get_node(forest, mcmd->cache_file);
+
+ dag_add_relation(forest, curNode, obNode,
+ DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Cache File Modifier");
+ }
+
+ UNUSED_VARS(bmain, scene, ob);
+}
+
+static void updateDepsgraph(ModifierData *md,
+ struct Main *bmain,
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
+
+ if (mcmd->cache_file != NULL) {
+ DEG_add_cache_relation(node, mcmd->cache_file, DEG_COMPONENT_CACHE, "Mesh Cache File");
+ }
+
+ UNUSED_VARS(bmain, scene, ob);
+}
+
+ModifierTypeInfo modifierType_MeshSequenceCache = {
+ /* name */ "Mesh Sequence Cache",
+ /* structName */ "MeshSeqCacheModifierData",
+ /* structSize */ sizeof(MeshSeqCacheModifierData),
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh |
+ eModifierTypeFlag_AcceptsCVs,
+ /* copyData */ copyData,
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ applyModifier,
+ /* applyModifierEM */ NULL,
+ /* initData */ initData,
+ /* requiredDataMask */ NULL,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ dependsOnTime,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index f9291fb077f..93414562ccf 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -286,5 +286,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(DataTransfer);
INIT_TYPE(NormalEdit);
INIT_TYPE(CorrectiveSmooth);
+ INIT_TYPE(MeshSequenceCache);
#undef INIT_TYPE
}
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 9d30c285dbf..ab65b73f0a6 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -376,7 +376,8 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
s->flags |= CLOTH_SPRING_FLAG_NEEDED;
// current_position = xold + t * (newposition - xold)
- interp_v3_v3v3(goal_x, verts[s->ij].xold, verts[s->ij].xconst, time);
+ /* divide by time_scale to prevent goal vertices' delta locations from being multiplied */
+ interp_v3_v3v3(goal_x, verts[s->ij].xold, verts[s->ij].xconst, time / parms->time_scale);
sub_v3_v3v3(goal_v, verts[s->ij].xconst, verts[s->ij].xold); // distance covered over dt==1
scaling = parms->goalspring + s->stiffness * fabsf(parms->max_struct - parms->goalspring);
@@ -1004,6 +1005,8 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, EffectorCo
float v[3];
sub_v3_v3v3(v, verts[i].xconst, verts[i].xold);
// mul_v3_fl(v, clmd->sim_parms->stepsPerFrame);
+ /* divide by time_scale to prevent constrained velocities from being multiplied */
+ mul_v3_fl(v, 1.0f / clmd->sim_parms->time_scale);
BPH_mass_spring_set_velocity(id, i, v);
}
}
@@ -1070,7 +1073,8 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, EffectorCo
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
float x[3];
- interp_v3_v3v3(x, verts[i].xold, verts[i].xconst, step + dt);
+ /* divide by time_scale to prevent pinned vertices' delta locations from being multiplied */
+ interp_v3_v3v3(x, verts[i].xold, verts[i].xconst, (step + dt) / clmd->sim_parms->time_scale);
BPH_mass_spring_set_position(id, i, x);
}
}
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 4006816e788..3148dab3c50 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -32,6 +32,7 @@
#ifndef __BPY_EXTERN_H__
#define __BPY_EXTERN_H__
+struct PathResolvedRNA;
struct Text; /* defined in DNA_text_types.h */
struct ID; /* DNA_ID.h */
struct Object; /* DNA_object_types.h */
@@ -85,7 +86,7 @@ void BPY_modules_load_user(struct bContext *C);
void BPY_app_handlers_reset(const short do_all);
void BPY_driver_reset(void);
-float BPY_driver_exec(struct ChannelDriver *driver, const float evaltime);
+float BPY_driver_exec(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime);
void BPY_DECREF(void *pyob_ptr); /* Py_DECREF() */
void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr);
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c
index 551a66d1ed8..8f287918a4a 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.c
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.c
@@ -581,7 +581,7 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
switch (slot->slot_subtype.map) {
case BMO_OP_SLOT_SUBTYPE_MAP_ELEM:
{
- item = PyDict_New();
+ item = _PyDict_NewPresized(slot_hash ? BLI_ghash_size(slot_hash) : 0);
if (slot_hash) {
GHASH_ITER (hash_iter, slot_hash) {
BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
@@ -599,7 +599,7 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
}
case BMO_OP_SLOT_SUBTYPE_MAP_FLT:
{
- item = PyDict_New();
+ item = _PyDict_NewPresized(slot_hash ? BLI_ghash_size(slot_hash) : 0);
if (slot_hash) {
GHASH_ITER (hash_iter, slot_hash) {
BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
@@ -617,7 +617,7 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
}
case BMO_OP_SLOT_SUBTYPE_MAP_INT:
{
- item = PyDict_New();
+ item = _PyDict_NewPresized(slot_hash ? BLI_ghash_size(slot_hash) : 0);
if (slot_hash) {
GHASH_ITER (hash_iter, slot_hash) {
BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
@@ -635,7 +635,7 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
}
case BMO_OP_SLOT_SUBTYPE_MAP_BOOL:
{
- item = PyDict_New();
+ item = _PyDict_NewPresized(slot_hash ? BLI_ghash_size(slot_hash) : 0);
if (slot_hash) {
GHASH_ITER (hash_iter, slot_hash) {
BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 11646f3f3df..2e15b7b1413 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -98,7 +98,7 @@ static PyObject *idprop_py_from_idp_array(ID *id, IDProperty *prop)
static PyObject *idprop_py_from_idp_idparray(ID *id, IDProperty *prop)
{
- PyObject *seq = PyList_New(prop->len), *wrap;
+ PyObject *seq = PyList_New(prop->len);
IDProperty *array = IDP_IDPArray(prop);
int i;
@@ -110,10 +110,13 @@ static PyObject *idprop_py_from_idp_idparray(ID *id, IDProperty *prop)
}
for (i = 0; i < prop->len; i++) {
- wrap = BPy_IDGroup_WrapData(id, array++, prop);
+ PyObject *wrap = BPy_IDGroup_WrapData(id, array++, prop);
- if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
+ /* BPy_IDGroup_MapDataToPy sets the error */
+ if (UNLIKELY(wrap == NULL)) {
+ Py_DECREF(seq);
return NULL;
+ }
PyList_SET_ITEM(seq, i, wrap);
}
@@ -378,8 +381,10 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group,
}
else if (PyUnicode_Check(ob)) {
#ifdef USE_STRING_COERCE
+ Py_ssize_t value_size;
PyObject *value_coerce = NULL;
- val.string.str = PyC_UnicodeAsByte(ob, &value_coerce);
+ val.string.str = PyC_UnicodeAsByteAndSize(ob, &value_size, &value_coerce);
+ val.string.len = (int)value_size + 1;
val.string.subtype = IDP_STRING_SUB_UTF8;
prop = IDP_New(IDP_STRING, &val, name);
Py_XDECREF(value_coerce);
@@ -657,7 +662,7 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
}
case IDP_IDPARRAY:
{
- PyObject *seq = PyList_New(prop->len), *wrap;
+ PyObject *seq = PyList_New(prop->len);
IDProperty *array = IDP_IDPArray(prop);
int i;
@@ -669,10 +674,13 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
}
for (i = 0; i < prop->len; i++) {
- wrap = BPy_IDGroup_MapDataToPy(array++);
+ PyObject *wrap = BPy_IDGroup_MapDataToPy(array++);
- if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
+ /* BPy_IDGroup_MapDataToPy sets the error */
+ if (UNLIKELY(wrap == NULL)) {
+ Py_DECREF(seq);
return NULL;
+ }
PyList_SET_ITEM(seq, i, wrap);
}
@@ -680,14 +688,17 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
}
case IDP_GROUP:
{
- PyObject *dict = PyDict_New(), *wrap;
+ PyObject *dict = _PyDict_NewPresized(prop->len);
IDProperty *loop;
for (loop = prop->data.group.first; loop; loop = loop->next) {
- wrap = BPy_IDGroup_MapDataToPy(loop);
+ PyObject *wrap = BPy_IDGroup_MapDataToPy(loop);
- if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
+ /* BPy_IDGroup_MapDataToPy sets the error */
+ if (UNLIKELY(wrap == NULL)) {
+ Py_DECREF(dict);
return NULL;
+ }
PyDict_SetItemString(dict, loop->name, wrap);
Py_DECREF(wrap);
@@ -702,7 +713,17 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
return NULL;
}
-static PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value)
+PyDoc_STRVAR(BPy_IDGroup_pop_doc,
+".. method:: pop(key)\n"
+"\n"
+" Remove an item from the group, returning a Python representation.\n"
+"\n"
+" :raises KeyError: When the item doesn't exist.\n"
+"\n"
+" :arg key: Name of item to remove.\n"
+" :type key: string\n"
+);
+static PyObject *BPy_IDGroup_pop(BPy_IDProperty *self, PyObject *value)
{
IDProperty *idprop;
PyObject *pyform;
@@ -735,7 +756,12 @@ static PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value)
return NULL;
}
-static PyObject *BPy_IDGroup_IterItems(BPy_IDProperty *self)
+PyDoc_STRVAR(BPy_IDGroup_iter_items_doc,
+".. method:: iteritems()\n"
+"\n"
+" Iterate through the items in the dict; behaves like dictionary method iteritems.\n"
+);
+static PyObject *BPy_IDGroup_iter_items(BPy_IDProperty *self)
{
BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
iter->group = self;
@@ -829,18 +855,32 @@ PyObject *BPy_Wrap_GetItems(ID *id, IDProperty *prop)
return seq;
}
-
-static PyObject *BPy_IDGroup_GetKeys(BPy_IDProperty *self)
+PyDoc_STRVAR(BPy_IDGroup_keys_doc,
+".. method:: keys()\n"
+"\n"
+" Return the keys associated with this group as a list of strings.\n"
+);
+static PyObject *BPy_IDGroup_keys(BPy_IDProperty *self)
{
return BPy_Wrap_GetKeys(self->prop);
}
-static PyObject *BPy_IDGroup_GetValues(BPy_IDProperty *self)
+PyDoc_STRVAR(BPy_IDGroup_values_doc,
+".. method:: values()\n"
+"\n"
+" Return the values associated with this group.\n"
+);
+static PyObject *BPy_IDGroup_values(BPy_IDProperty *self)
{
return BPy_Wrap_GetValues(self->id, self->prop);
}
-static PyObject *BPy_IDGroup_GetItems(BPy_IDProperty *self)
+PyDoc_STRVAR(BPy_IDGroup_items_doc,
+".. method:: items()\n"
+"\n"
+" Return the items associated with this group.\n"
+);
+static PyObject *BPy_IDGroup_items(BPy_IDProperty *self)
{
return BPy_Wrap_GetItems(self->id, self->prop);
}
@@ -859,7 +899,15 @@ static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value)
return IDP_GetPropertyFromGroup(self->prop, name) ? 1 : 0;
}
-static PyObject *BPy_IDGroup_Update(BPy_IDProperty *self, PyObject *value)
+PyDoc_STRVAR(BPy_IDGroup_update_doc,
+".. method:: update(other)\n"
+"\n"
+" Update key, values.\n"
+"\n"
+" :arg other: Updates the values in the group with this.\n"
+" :type other: :class:`IDPropertyGroup` or dict\n"
+);
+static PyObject *BPy_IDGroup_update(BPy_IDProperty *self, PyObject *value)
{
PyObject *pkey, *pval;
Py_ssize_t i = 0;
@@ -890,19 +938,33 @@ static PyObject *BPy_IDGroup_Update(BPy_IDProperty *self, PyObject *value)
Py_RETURN_NONE;
}
+PyDoc_STRVAR(BPy_IDGroup_to_dict_doc,
+".. method:: to_dict()\n"
+"\n"
+" Return a purely python version of the group.\n"
+);
static PyObject *BPy_IDGroup_to_dict(BPy_IDProperty *self)
{
return BPy_IDGroup_MapDataToPy(self->prop);
}
+PyDoc_STRVAR(BPy_IDGroup_clear_doc,
+".. method:: clear()\n"
+"\n"
+" Clear all members from this group.\n"
+);
static PyObject *BPy_IDGroup_clear(BPy_IDProperty *self)
{
IDP_ClearProperty(self->prop);
Py_RETURN_NONE;
}
-/* Matches python dict.get(key, [default]) */
-static PyObject *BPy_IDGroup_Get(BPy_IDProperty *self, PyObject *args)
+PyDoc_STRVAR(BPy_IDGroup_get_doc,
+".. method:: get(key, default=None)\n"
+"\n"
+" Return the value for key, if it exists, else default.\n"
+);
+static PyObject *BPy_IDGroup_get(BPy_IDProperty *self, PyObject *args)
{
IDProperty *idprop;
const char *key;
@@ -923,24 +985,15 @@ static PyObject *BPy_IDGroup_Get(BPy_IDProperty *self, PyObject *args)
}
static struct PyMethodDef BPy_IDGroup_methods[] = {
- {"pop", (PyCFunction)BPy_IDGroup_Pop, METH_O,
- "pop an item from the group; raises KeyError if the item doesn't exist"},
- {"iteritems", (PyCFunction)BPy_IDGroup_IterItems, METH_NOARGS,
- "iterate through the items in the dict; behaves like dictionary method iteritems"},
- {"keys", (PyCFunction)BPy_IDGroup_GetKeys, METH_NOARGS,
- "get the keys associated with this group as a list of strings"},
- {"values", (PyCFunction)BPy_IDGroup_GetValues, METH_NOARGS,
- "get the values associated with this group"},
- {"items", (PyCFunction)BPy_IDGroup_GetItems, METH_NOARGS,
- "get the items associated with this group"},
- {"update", (PyCFunction)BPy_IDGroup_Update, METH_O,
- "updates the values in the group with the values of another or a dict"},
- {"get", (PyCFunction)BPy_IDGroup_Get, METH_VARARGS,
- "idprop.get(k[,d]) -> idprop[k] if k in idprop, else d. d defaults to None"},
- {"to_dict", (PyCFunction)BPy_IDGroup_to_dict, METH_NOARGS,
- "return a purely python version of the group"},
- {"clear", (PyCFunction)BPy_IDGroup_clear, METH_NOARGS,
- "clear all members from this group"},
+ {"pop", (PyCFunction)BPy_IDGroup_pop, METH_O, BPy_IDGroup_pop_doc},
+ {"iteritems", (PyCFunction)BPy_IDGroup_iter_items, METH_NOARGS, BPy_IDGroup_iter_items_doc},
+ {"keys", (PyCFunction)BPy_IDGroup_keys, METH_NOARGS, BPy_IDGroup_keys_doc},
+ {"values", (PyCFunction)BPy_IDGroup_values, METH_NOARGS, BPy_IDGroup_values_doc},
+ {"items", (PyCFunction)BPy_IDGroup_items, METH_NOARGS, BPy_IDGroup_items_doc},
+ {"update", (PyCFunction)BPy_IDGroup_update, METH_O, BPy_IDGroup_update_doc},
+ {"get", (PyCFunction)BPy_IDGroup_get, METH_VARARGS, BPy_IDGroup_get_doc},
+ {"to_dict", (PyCFunction)BPy_IDGroup_to_dict, METH_NOARGS, BPy_IDGroup_to_dict_doc},
+ {"clear", (PyCFunction)BPy_IDGroup_clear, METH_NOARGS, BPy_IDGroup_clear_doc},
{NULL, NULL, 0, NULL}
};
@@ -1049,7 +1102,10 @@ static PyObject *BPy_IDArray_repr(BPy_IDArray *self)
return PyUnicode_FromFormat("<bpy id property array [%d]>", self->prop->len);
}
-static PyObject *BPy_IDArray_GetType(BPy_IDArray *self)
+PyDoc_STRVAR(BPy_IDArray_get_typecode_doc,
+"The type of the data in the array {'f': float, 'd': double, 'i': int}."
+);
+static PyObject *BPy_IDArray_get_typecode(BPy_IDArray *self)
{
switch (self->prop->subtype) {
case IDP_FLOAT: return PyUnicode_FromString("f");
@@ -1066,18 +1122,22 @@ static PyObject *BPy_IDArray_GetType(BPy_IDArray *self)
static PyGetSetDef BPy_IDArray_getseters[] = {
/* matches pythons array.typecode */
- {(char *)"typecode", (getter)BPy_IDArray_GetType, (setter)NULL, (char *)"The type of the data in the array, is an int.", NULL},
+ {(char *)"typecode", (getter)BPy_IDArray_get_typecode, (setter)NULL, BPy_IDArray_get_typecode_doc, NULL},
{NULL, NULL, NULL, NULL, NULL},
};
+PyDoc_STRVAR(BPy_IDArray_to_list_doc,
+".. method:: to_list()\n"
+"\n"
+" Return the array as a list.\n"
+);
static PyObject *BPy_IDArray_to_list(BPy_IDArray *self)
{
return BPy_IDGroup_MapDataToPy(self->prop);
}
static PyMethodDef BPy_IDArray_methods[] = {
- {"to_list", (PyCFunction)BPy_IDArray_to_list, METH_NOARGS,
- "return the array as a list"},
+ {"to_list", (PyCFunction)BPy_IDArray_to_list, METH_NOARGS, BPy_IDArray_to_list_doc},
{NULL, NULL, 0, NULL}
};
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 72dec55e50b..7b2d58a1268 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -540,6 +540,35 @@ PyObject *PyC_ExceptionBuffer_Simple(void)
}
/* string conversion, escape non-unicode chars, coerce must be set to NULL */
+const char *PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce)
+{
+ const char *result;
+
+ result = _PyUnicode_AsStringAndSize(py_str, size);
+
+ if (result) {
+ /* 99% of the time this is enough but we better support non unicode
+ * chars since blender doesnt limit this */
+ return result;
+ }
+ else {
+ PyErr_Clear();
+
+ if (PyBytes_Check(py_str)) {
+ *size = PyBytes_GET_SIZE(py_str);
+ return PyBytes_AS_STRING(py_str);
+ }
+ else if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) {
+ *size = PyBytes_GET_SIZE(*coerce);
+ return PyBytes_AS_STRING(*coerce);
+ }
+ else {
+ /* leave error raised from EncodeFS */
+ return NULL;
+ }
+ }
+}
+
const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
{
const char *result;
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index a06a717ecbc..04cfc8801eb 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -53,6 +53,7 @@ void PyC_List_Fill(PyObject *list, PyObject *value);
PyObject * PyC_UnicodeFromByte(const char *str);
PyObject * PyC_UnicodeFromByteAndSize(const char *str, Py_ssize_t size);
const char * PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */
+const char * PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce);
/* name namespace function for bpy & bge */
PyObject * PyC_DefaultNameSpace(const char *filename);
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 2715d2c5992..038c1e7eb10 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -49,6 +49,7 @@ set(SRC
gpu_offscreen.c
bpy.c
bpy_app.c
+ bpy_app_alembic.c
bpy_app_build_options.c
bpy_app_ffmpeg.c
bpy_app_handlers.c
@@ -82,6 +83,7 @@ set(SRC
gpu.h
bpy.h
bpy_app.h
+ bpy_app_alembic.h
bpy_app_build_options.h
bpy_app_ffmpeg.h
bpy_app_handlers.h
@@ -264,6 +266,10 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
+if(WITH_ALEMBIC)
+ add_definitions(-DWITH_ALEMBIC)
+endif()
+
if(WITH_OPENCOLORIO)
add_definitions(-DWITH_OCIO)
endif()
@@ -275,6 +281,13 @@ if(WITH_OPENVDB)
)
endif()
+if(WITH_ALEMBIC)
+ add_definitions(-DWITH_ALEMBIC)
+ list(APPEND INC
+ ../../alembic
+ )
+endif()
+
if(WITH_OPENIMAGEIO)
add_definitions(-DWITH_OPENIMAGEIO)
list(APPEND INC
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 727d980b182..78cb537cccd 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -33,6 +33,7 @@
#include "bpy_app.h"
+#include "bpy_app_alembic.h"
#include "bpy_app_ffmpeg.h"
#include "bpy_app_ocio.h"
#include "bpy_app_oiio.h"
@@ -104,6 +105,7 @@ static PyStructSequence_Field app_info_fields[] = {
{(char *)"build_system", (char *)"Build system used"},
/* submodules */
+ {(char *)"alembic", (char *)"Alembic library information backend"},
{(char *)"ffmpeg", (char *)"FFmpeg library information backend"},
{(char *)"ocio", (char *)"OpenColorIO library information backend"},
{(char *)"oiio", (char *)"OpenImageIO library information backend"},
@@ -182,6 +184,7 @@ static PyObject *make_app_info(void)
SetBytesItem("Unknown");
#endif
+ SetObjItem(BPY_app_alembic_struct());
SetObjItem(BPY_app_ffmpeg_struct());
SetObjItem(BPY_app_ocio_struct());
SetObjItem(BPY_app_oiio_struct());
diff --git a/source/blender/python/intern/bpy_app_alembic.c b/source/blender/python/intern/bpy_app_alembic.c
new file mode 100644
index 00000000000..90e6a02b418
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_alembic.c
@@ -0,0 +1,113 @@
+/*
+ * ***** 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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_alembic.c
+ * \ingroup pythonintern
+ */
+
+#include <Python.h>
+#include "BLI_utildefines.h"
+
+#include "bpy_app_alembic.h"
+
+#ifdef WITH_ALEMBIC
+# include "ABC_alembic.h"
+#endif
+
+static PyTypeObject BlenderAppABCType;
+
+static PyStructSequence_Field app_alembic_info_fields[] = {
+ {(char *)"supported", (char *)"Boolean, True when Blender is built with Alembic support"},
+ {(char *)"version", (char *)"The Alembic version as a tuple of 3 numbers"},
+ {(char *)"version_string", (char *)"The Alembic version formatted as a string"},
+ {NULL}
+};
+
+static PyStructSequence_Desc app_alembic_info_desc = {
+ (char *)"bpy.app.alembic", /* name */
+ (char *)"This module contains information about Alembic blender is linked against", /* doc */
+ app_alembic_info_fields, /* fields */
+ ARRAY_SIZE(app_alembic_info_fields) - 1
+};
+
+static PyObject *make_alembic_info(void)
+{
+ PyObject *alembic_info = PyStructSequence_New(&BlenderAppABCType);
+
+ if (alembic_info == NULL) {
+ return NULL;
+ }
+
+ int pos = 0;
+
+#ifndef WITH_ALEMBIC
+# define SetStrItem(str) \
+ PyStructSequence_SET_ITEM(alembic_info, pos++, PyUnicode_FromString(str))
+#endif
+
+#define SetObjItem(obj) \
+ PyStructSequence_SET_ITEM(alembic_info, pos++, obj)
+
+#ifdef WITH_ALEMBIC
+ const int curversion = ABC_get_version();
+ const int major = curversion / 10000;
+ const int minor = (curversion / 100) - (major * 100);
+ const int patch = curversion - ((curversion / 100 ) * 100);
+
+ SetObjItem(PyBool_FromLong(1));
+ SetObjItem(Py_BuildValue("(iii)", major, minor, patch));
+ SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", major, minor, patch));
+#else
+ SetObjItem(PyBool_FromLong(0));
+ SetObjItem(Py_BuildValue("(iii)", 0, 0, 0));
+ SetStrItem("Unknown");
+#endif
+
+ if (PyErr_Occurred()) {
+ Py_CLEAR(alembic_info);
+ return NULL;
+ }
+
+#undef SetStrItem
+#undef SetObjItem
+
+ return alembic_info;
+}
+
+PyObject *BPY_app_alembic_struct(void)
+{
+ PyStructSequence_InitType(&BlenderAppABCType, &app_alembic_info_desc);
+
+ PyObject *ret = make_alembic_info();
+
+ /* prevent user from creating new instances */
+ BlenderAppABCType.tp_init = NULL;
+ BlenderAppABCType.tp_new = NULL;
+ BlenderAppABCType.tp_hash = (hashfunc)_Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+
+ return ret;
+}
diff --git a/source/blender/python/intern/bpy_app_alembic.h b/source/blender/python/intern/bpy_app_alembic.h
new file mode 100644
index 00000000000..8cc647a77df
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_alembic.h
@@ -0,0 +1,38 @@
+/*
+ * ***** 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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_alembic.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_APP_ALEMBIC_H__
+#define __BPY_APP_ALEMBIC_H__
+
+PyObject *BPY_app_alembic_struct(void);
+
+#endif /* __BPY_APP_ALEMBIC_H__ */
+
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index 4c186aab100..a6b98567a9a 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -69,6 +69,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{(char *)"player", NULL},
{(char *)"openmp", NULL},
{(char *)"openvdb", NULL},
+ {(char *)"alembic", NULL},
{NULL}
};
@@ -303,6 +304,12 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
+#ifdef WITH_ALEMBIC
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#undef SetObjIncref
return builtopts_info;
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index b90deafb377..6ba858f0228 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -675,7 +675,7 @@ static PyObject *app_translations_new(PyTypeObject *type, PyObject *UNUSED(args)
_translations->contexts = app_translations_contexts_make();
- py_ctxts = PyDict_New();
+ py_ctxts = _PyDict_NewPresized(ARRAY_SIZE(_contexts));
for (ctxt = _contexts; ctxt->c_id; ctxt++) {
PyObject *val = PyUnicode_FromString(ctxt->py_id);
PyDict_SetItemString(py_ctxts, ctxt->c_id, val);
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index 65b6bd501ce..c8ce7b2f770 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -44,6 +44,8 @@
#include "bpy_rna_driver.h" /* for pyrna_driver_get_variable_value */
+#include "bpy_intern_string.h"
+
#include "bpy_driver.h"
extern void BPY_update_rna_module(void);
@@ -97,26 +99,48 @@ int bpy_pydriver_create_dict(void)
}
/* note, this function should do nothing most runs, only when changing frame */
-static PyObject *bpy_pydriver_InternStr__frame = NULL;
/* not thread safe but neither is python */
-static float bpy_pydriver_evaltime_prev = FLT_MAX;
-
-static void bpy_pydriver_update_dict(const float evaltime)
+static struct {
+ float evaltime;
+
+ /* borrowed reference to the 'self' in 'bpy_pydriver_Dict'
+ * keep for as long as the same self is used. */
+ PyObject *self;
+} g_pydriver_state_prev = {
+ .evaltime = FLT_MAX,
+ .self = NULL,
+};
+
+static void bpy_pydriver_namespace_update_frame(const float evaltime)
{
- if (bpy_pydriver_evaltime_prev != evaltime) {
+ if (g_pydriver_state_prev.evaltime != evaltime) {
+ PyObject *item = PyFloat_FromDouble(evaltime);
+ PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_frame, item);
+ Py_DECREF(item);
- /* currently only update the frame */
- if (bpy_pydriver_InternStr__frame == NULL) {
- bpy_pydriver_InternStr__frame = PyUnicode_FromString("frame");
- }
+ g_pydriver_state_prev.evaltime = evaltime;
+ }
+}
- PyObject *item = PyFloat_FromDouble(evaltime);
- PyDict_SetItem(bpy_pydriver_Dict,
- bpy_pydriver_InternStr__frame,
- item);
+static void bpy_pydriver_namespace_update_self(struct PathResolvedRNA *anim_rna)
+{
+ if ((g_pydriver_state_prev.self == NULL) ||
+ (pyrna_driver_is_equal_anim_rna(anim_rna, g_pydriver_state_prev.self) == false))
+ {
+ PyObject *item = pyrna_driver_self_from_anim_rna(anim_rna);
+ PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_self, item);
Py_DECREF(item);
- bpy_pydriver_evaltime_prev = evaltime;
+ g_pydriver_state_prev.self = item;
+ }
+}
+
+static void bpy_pydriver_namespace_clear_self(void)
+{
+ if (g_pydriver_state_prev.self) {
+ PyDict_DelItem(bpy_pydriver_Dict, bpy_intern_str_self);
+
+ g_pydriver_state_prev.self = NULL;
}
}
@@ -139,11 +163,10 @@ void BPY_driver_reset(void)
bpy_pydriver_Dict = NULL;
}
- if (bpy_pydriver_InternStr__frame) {
- Py_DECREF(bpy_pydriver_InternStr__frame);
- bpy_pydriver_InternStr__frame = NULL;
- bpy_pydriver_evaltime_prev = FLT_MAX;
- }
+ g_pydriver_state_prev.evaltime = FLT_MAX;
+
+ /* freed when clearing driver dict */
+ g_pydriver_state_prev.self = NULL;
if (use_gil)
PyGILState_Release(gilstate);
@@ -174,7 +197,7 @@ static void pydriver_error(ChannelDriver *driver)
* now release the GIL on python operator execution instead, using
* PyEval_SaveThread() / PyEval_RestoreThread() so we don't lock up blender.
*/
-float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
+float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime)
{
PyObject *driver_vars = NULL;
PyObject *retval = NULL;
@@ -224,8 +247,14 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
}
/* update global namespace */
- bpy_pydriver_update_dict(evaltime);
+ bpy_pydriver_namespace_update_frame(evaltime);
+ if (driver->flag & DRIVER_FLAG_USE_SELF) {
+ bpy_pydriver_namespace_update_self(anim_rna);
+ }
+ else {
+ bpy_pydriver_namespace_clear_self();
+ }
if (driver->expr_comp == NULL)
driver->flag |= DRIVER_FLAG_RECOMPILE;
@@ -264,7 +293,7 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
}
/* add target values to a dict that will be used as '__locals__' dict */
- driver_vars = PyDict_New();
+ driver_vars = _PyDict_NewPresized(PyTuple_GET_SIZE(expr_vars));
for (dvar = driver->variables.first, i = 0; dvar; dvar = dvar->next) {
PyObject *driver_arg = NULL;
diff --git a/source/blender/python/intern/bpy_driver.h b/source/blender/python/intern/bpy_driver.h
index 1fccec7e1b2..017a6fe89c5 100644
--- a/source/blender/python/intern/bpy_driver.h
+++ b/source/blender/python/intern/bpy_driver.h
@@ -28,12 +28,13 @@
#define __BPY_DRIVER_H__
struct ChannelDriver;
+struct PathResolvedRNA;
int bpy_pydriver_create_dict(void);
extern PyObject *bpy_pydriver_Dict;
/* externals */
-float BPY_driver_exec(struct ChannelDriver *driver, const float evaltime);
+float BPY_driver_exec(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime);
void BPY_driver_reset(void);
#endif /* __BPY_DRIVER_H__ */
diff --git a/source/blender/python/intern/bpy_intern_string.c b/source/blender/python/intern/bpy_intern_string.c
index fd32c91a480..ac0100fa75d 100644
--- a/source/blender/python/intern/bpy_intern_string.c
+++ b/source/blender/python/intern/bpy_intern_string.c
@@ -34,7 +34,7 @@
#include "BLI_utildefines.h"
-static PyObject *bpy_intern_str_arr[11];
+static PyObject *bpy_intern_str_arr[13];
PyObject *bpy_intern_str_register;
PyObject *bpy_intern_str_unregister;
@@ -43,6 +43,8 @@ PyObject *bpy_intern_str_bl_property;
PyObject *bpy_intern_str_bpy_types;
PyObject *bpy_intern_str_order;
PyObject *bpy_intern_str_attr;
+PyObject *bpy_intern_str_self;
+PyObject *bpy_intern_str_frame;
PyObject *bpy_intern_str___slots__;
PyObject *bpy_intern_str___name__;
PyObject *bpy_intern_str___doc__;
@@ -62,6 +64,8 @@ void bpy_intern_string_init(void)
BPY_INTERN_STR(bpy_intern_str_bpy_types, "bpy.types");
BPY_INTERN_STR(bpy_intern_str_order, "order");
BPY_INTERN_STR(bpy_intern_str_attr, "attr");
+ BPY_INTERN_STR(bpy_intern_str_self, "self");
+ BPY_INTERN_STR(bpy_intern_str_frame, "frame");
BPY_INTERN_STR(bpy_intern_str___slots__, "__slots__");
BPY_INTERN_STR(bpy_intern_str___name__, "__name__");
BPY_INTERN_STR(bpy_intern_str___doc__, "__doc__");
diff --git a/source/blender/python/intern/bpy_intern_string.h b/source/blender/python/intern/bpy_intern_string.h
index f4f4560dbfd..394e84d89bd 100644
--- a/source/blender/python/intern/bpy_intern_string.h
+++ b/source/blender/python/intern/bpy_intern_string.h
@@ -37,6 +37,8 @@ extern PyObject *bpy_intern_str_bl_property;
extern PyObject *bpy_intern_str_bpy_types;
extern PyObject *bpy_intern_str_order;
extern PyObject *bpy_intern_str_attr;
+extern PyObject *bpy_intern_str_self;
+extern PyObject *bpy_intern_str_frame;
extern PyObject *bpy_intern_str___slots__;
extern PyObject *bpy_intern_str___name__;
extern PyObject *bpy_intern_str___doc__;
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index 37a7e0e23dd..ec69abbb1df 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -210,7 +210,7 @@ static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *
ret->flag = ((is_link ? FILE_LINK : 0) |
(is_rel ? FILE_RELPATH : 0));
- ret->dict = PyDict_New();
+ ret->dict = _PyDict_NewPresized(MAX_LIBARRAY);
return (PyObject *)ret;
}
@@ -240,7 +240,7 @@ static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args))
{
PyObject *ret;
BPy_Library *self_from;
- PyObject *from_dict = PyDict_New();
+ PyObject *from_dict = _PyDict_NewPresized(MAX_LIBARRAY);
ReportList reports;
BKE_reports_init(&reports, RPT_STORE);
diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c
index 482508a8d85..b4c0de51c04 100644
--- a/source/blender/python/intern/bpy_rna_driver.c
+++ b/source/blender/python/intern/bpy_rna_driver.c
@@ -77,3 +77,24 @@ PyObject *pyrna_driver_get_variable_value(
return driver_arg;
}
+
+PyObject *pyrna_driver_self_from_anim_rna(PathResolvedRNA *anim_rna)
+{
+ return pyrna_struct_CreatePyObject(&anim_rna->ptr);
+}
+
+bool pyrna_driver_is_equal_anim_rna(const PathResolvedRNA *anim_rna, const PyObject *py_anim_rna)
+{
+ if (BPy_StructRNA_Check(py_anim_rna)) {
+ const PointerRNA *ptr_a = &anim_rna->ptr;
+ const PointerRNA *ptr_b = &(((const BPy_StructRNA *)py_anim_rna)->ptr);
+
+ if ((ptr_a->id.data == ptr_b->id.data) &&
+ (ptr_a->type == ptr_b->type) &&
+ (ptr_a->data == ptr_b->data))
+ {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/source/blender/python/intern/bpy_rna_driver.h b/source/blender/python/intern/bpy_rna_driver.h
index 8deac2e4384..3f4bf2b9df5 100644
--- a/source/blender/python/intern/bpy_rna_driver.h
+++ b/source/blender/python/intern/bpy_rna_driver.h
@@ -27,7 +27,11 @@
struct ChannelDriver;
struct DriverTarget;
+struct PathResolvedRNA;
PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar);
+PyObject *pyrna_driver_self_from_anim_rna(struct PathResolvedRNA *anim_rna);
+bool pyrna_driver_is_equal_anim_rna(const struct PathResolvedRNA *anim_rna, const PyObject *py_anim_rna);
+
#endif /* __BPY_RNA_DRIVER_H__ */
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index 104e3e47646..31189ba4dee 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -198,7 +198,7 @@ static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *
PyObject **subset_array = PySequence_Fast_ITEMS(subset_fast);
Py_ssize_t subset_len = PySequence_Fast_GET_SIZE(subset_fast);
- data_cb.user_map = PyDict_New();
+ data_cb.user_map = _PyDict_NewPresized(subset_len);
data_cb.is_subset = true;
for (; subset_len; subset_array++, subset_len--) {
PyObject *set = PySet_New(NULL);
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 7b6fa466fce..afc8a30a6b5 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -2324,6 +2324,20 @@ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure
return 0;
}
+/* XYZW -> 0123 */
+#define AXIS_FROM_CHAR(a) (((a) != 'W') ? ((a) - 'X') : 3)
+
+#define _VA_SWIZZLE_1(a) ( \
+ ((AXIS_FROM_CHAR(a) | SWIZZLE_VALID_AXIS)))
+#define _VA_SWIZZLE_2(a, b) (_VA_SWIZZLE_1(a) | \
+ ((AXIS_FROM_CHAR(b) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS)))
+#define _VA_SWIZZLE_3(a, b, c) (_VA_SWIZZLE_2(a, b) | \
+ ((AXIS_FROM_CHAR(c) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))
+#define _VA_SWIZZLE_4(a, b, c, d) (_VA_SWIZZLE_3(a, b, c) | \
+ ((AXIS_FROM_CHAR(d) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3)))
+
+#define SWIZZLE(...) SET_INT_IN_POINTER(VA_NARGS_CALL_OVERLOAD(_VA_SWIZZLE_, __VA_ARGS__))
+
/*****************************************************************************/
/* Python attributes get/set structure: */
/*****************************************************************************/
@@ -2340,385 +2354,409 @@ static PyGetSetDef Vector_getseters[] = {
{(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
/* autogenerated swizzle attrs, see python script below */
- {(char *)"xx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 36
- {(char *)"xxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 292
- {(char *)"xxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2340
- {(char *)"xxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2852
- {(char *)"xxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3364
- {(char *)"xxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3876
- {(char *)"xxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 356
- {(char *)"xxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2404
- {(char *)"xxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2916
- {(char *)"xxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3428
- {(char *)"xxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3940
- {(char *)"xxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 420
- {(char *)"xxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2468
- {(char *)"xxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2980
- {(char *)"xxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3492
- {(char *)"xxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4004
- {(char *)"xxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 484
- {(char *)"xxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2532
- {(char *)"xxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3044
- {(char *)"xxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3556
- {(char *)"xxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4068
- {(char *)"xy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 44
- {(char *)"xyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 300
- {(char *)"xyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2348
- {(char *)"xyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2860
- {(char *)"xyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3372
- {(char *)"xyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3884
- {(char *)"xyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 364
- {(char *)"xyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2412
- {(char *)"xyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2924
- {(char *)"xyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3436
- {(char *)"xyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3948
- {(char *)"xyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 428
- {(char *)"xyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2476
- {(char *)"xyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2988
- {(char *)"xyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3500
- {(char *)"xyzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4012
- {(char *)"xyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 492
- {(char *)"xywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2540
- {(char *)"xywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3052
- {(char *)"xywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3564
- {(char *)"xyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4076
- {(char *)"xz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 52
- {(char *)"xzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 308
- {(char *)"xzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2356
- {(char *)"xzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2868
- {(char *)"xzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3380
- {(char *)"xzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3892
- {(char *)"xzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 372
- {(char *)"xzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2420
- {(char *)"xzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2932
- {(char *)"xzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3444
- {(char *)"xzyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3956
- {(char *)"xzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 436
- {(char *)"xzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2484
- {(char *)"xzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2996
- {(char *)"xzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3508
- {(char *)"xzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4020
- {(char *)"xzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 500
- {(char *)"xzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2548
- {(char *)"xzwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3060
- {(char *)"xzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3572
- {(char *)"xzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4084
- {(char *)"xw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 60
- {(char *)"xwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 316
- {(char *)"xwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2364
- {(char *)"xwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2876
- {(char *)"xwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3388
- {(char *)"xwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3900
- {(char *)"xwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 380
- {(char *)"xwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2428
- {(char *)"xwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2940
- {(char *)"xwyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3452
- {(char *)"xwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3964
- {(char *)"xwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 444
- {(char *)"xwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2492
- {(char *)"xwzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3004
- {(char *)"xwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3516
- {(char *)"xwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4028
- {(char *)"xww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 508
- {(char *)"xwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2556
- {(char *)"xwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3068
- {(char *)"xwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3580
- {(char *)"xwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4092
- {(char *)"yx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 37
- {(char *)"yxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 293
- {(char *)"yxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2341
- {(char *)"yxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2853
- {(char *)"yxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3365
- {(char *)"yxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3877
- {(char *)"yxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 357
- {(char *)"yxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2405
- {(char *)"yxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2917
- {(char *)"yxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3429
- {(char *)"yxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3941
- {(char *)"yxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 421
- {(char *)"yxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2469
- {(char *)"yxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2981
- {(char *)"yxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3493
- {(char *)"yxzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4005
- {(char *)"yxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 485
- {(char *)"yxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2533
- {(char *)"yxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3045
- {(char *)"yxwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3557
- {(char *)"yxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4069
- {(char *)"yy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 45
- {(char *)"yyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 301
- {(char *)"yyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2349
- {(char *)"yyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2861
- {(char *)"yyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3373
- {(char *)"yyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3885
- {(char *)"yyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 365
- {(char *)"yyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2413
- {(char *)"yyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2925
- {(char *)"yyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3437
- {(char *)"yyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3949
- {(char *)"yyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 429
- {(char *)"yyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2477
- {(char *)"yyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2989
- {(char *)"yyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3501
- {(char *)"yyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4013
- {(char *)"yyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 493
- {(char *)"yywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2541
- {(char *)"yywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3053
- {(char *)"yywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3565
- {(char *)"yyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4077
- {(char *)"yz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 53
- {(char *)"yzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 309
- {(char *)"yzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2357
- {(char *)"yzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2869
- {(char *)"yzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3381
- {(char *)"yzxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3893
- {(char *)"yzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 373
- {(char *)"yzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2421
- {(char *)"yzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2933
- {(char *)"yzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3445
- {(char *)"yzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3957
- {(char *)"yzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 437
- {(char *)"yzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2485
- {(char *)"yzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2997
- {(char *)"yzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3509
- {(char *)"yzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4021
- {(char *)"yzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 501
- {(char *)"yzwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2549
- {(char *)"yzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3061
- {(char *)"yzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3573
- {(char *)"yzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4085
- {(char *)"yw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 61
- {(char *)"ywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 317
- {(char *)"ywxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2365
- {(char *)"ywxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2877
- {(char *)"ywxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3389
- {(char *)"ywxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3901
- {(char *)"ywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 381
- {(char *)"ywyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2429
- {(char *)"ywyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2941
- {(char *)"ywyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3453
- {(char *)"ywyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3965
- {(char *)"ywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 445
- {(char *)"ywzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2493
- {(char *)"ywzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3005
- {(char *)"ywzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3517
- {(char *)"ywzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4029
- {(char *)"yww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 509
- {(char *)"ywwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2557
- {(char *)"ywwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3069
- {(char *)"ywwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3581
- {(char *)"ywww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4093
- {(char *)"zx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 38
- {(char *)"zxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 294
- {(char *)"zxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2342
- {(char *)"zxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2854
- {(char *)"zxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3366
- {(char *)"zxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3878
- {(char *)"zxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 358
- {(char *)"zxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2406
- {(char *)"zxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2918
- {(char *)"zxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3430
- {(char *)"zxyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3942
- {(char *)"zxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 422
- {(char *)"zxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2470
- {(char *)"zxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2982
- {(char *)"zxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3494
- {(char *)"zxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4006
- {(char *)"zxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 486
- {(char *)"zxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2534
- {(char *)"zxwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3046
- {(char *)"zxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3558
- {(char *)"zxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4070
- {(char *)"zy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 46
- {(char *)"zyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 302
- {(char *)"zyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2350
- {(char *)"zyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2862
- {(char *)"zyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3374
- {(char *)"zyxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3886
- {(char *)"zyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 366
- {(char *)"zyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2414
- {(char *)"zyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2926
- {(char *)"zyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3438
- {(char *)"zyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3950
- {(char *)"zyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 430
- {(char *)"zyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2478
- {(char *)"zyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2990
- {(char *)"zyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3502
- {(char *)"zyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4014
- {(char *)"zyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 494
- {(char *)"zywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2542
- {(char *)"zywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3054
- {(char *)"zywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3566
- {(char *)"zyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4078
- {(char *)"zz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 54
- {(char *)"zzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 310
- {(char *)"zzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2358
- {(char *)"zzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2870
- {(char *)"zzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3382
- {(char *)"zzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3894
- {(char *)"zzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 374
- {(char *)"zzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2422
- {(char *)"zzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2934
- {(char *)"zzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3446
- {(char *)"zzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3958
- {(char *)"zzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 438
- {(char *)"zzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2486
- {(char *)"zzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2998
- {(char *)"zzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3510
- {(char *)"zzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4022
- {(char *)"zzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 502
- {(char *)"zzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2550
- {(char *)"zzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3062
- {(char *)"zzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3574
- {(char *)"zzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4086
- {(char *)"zw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 62
- {(char *)"zwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 318
- {(char *)"zwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2366
- {(char *)"zwxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2878
- {(char *)"zwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3390
- {(char *)"zwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3902
- {(char *)"zwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 382
- {(char *)"zwyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2430
- {(char *)"zwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2942
- {(char *)"zwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3454
- {(char *)"zwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3966
- {(char *)"zwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 446
- {(char *)"zwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2494
- {(char *)"zwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3006
- {(char *)"zwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3518
- {(char *)"zwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4030
- {(char *)"zww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 510
- {(char *)"zwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2558
- {(char *)"zwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3070
- {(char *)"zwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3582
- {(char *)"zwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4094
- {(char *)"wx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 39
- {(char *)"wxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 295
- {(char *)"wxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2343
- {(char *)"wxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2855
- {(char *)"wxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3367
- {(char *)"wxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3879
- {(char *)"wxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 359
- {(char *)"wxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2407
- {(char *)"wxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2919
- {(char *)"wxyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3431
- {(char *)"wxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3943
- {(char *)"wxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 423
- {(char *)"wxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2471
- {(char *)"wxzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2983
- {(char *)"wxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3495
- {(char *)"wxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4007
- {(char *)"wxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 487
- {(char *)"wxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2535
- {(char *)"wxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3047
- {(char *)"wxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3559
- {(char *)"wxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4071
- {(char *)"wy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 47
- {(char *)"wyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 303
- {(char *)"wyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2351
- {(char *)"wyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2863
- {(char *)"wyxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3375
- {(char *)"wyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3887
- {(char *)"wyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 367
- {(char *)"wyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2415
- {(char *)"wyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2927
- {(char *)"wyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3439
- {(char *)"wyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3951
- {(char *)"wyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 431
- {(char *)"wyzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2479
- {(char *)"wyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2991
- {(char *)"wyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3503
- {(char *)"wyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4015
- {(char *)"wyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 495
- {(char *)"wywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2543
- {(char *)"wywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3055
- {(char *)"wywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3567
- {(char *)"wyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4079
- {(char *)"wz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 55
- {(char *)"wzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 311
- {(char *)"wzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2359
- {(char *)"wzxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2871
- {(char *)"wzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3383
- {(char *)"wzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3895
- {(char *)"wzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 375
- {(char *)"wzyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2423
- {(char *)"wzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2935
- {(char *)"wzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3447
- {(char *)"wzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3959
- {(char *)"wzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 439
- {(char *)"wzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2487
- {(char *)"wzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2999
- {(char *)"wzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3511
- {(char *)"wzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4023
- {(char *)"wzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 503
- {(char *)"wzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2551
- {(char *)"wzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3063
- {(char *)"wzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3575
- {(char *)"wzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4087
- {(char *)"ww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 63
- {(char *)"wwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 319
- {(char *)"wwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2367
- {(char *)"wwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2879
- {(char *)"wwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3391
- {(char *)"wwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3903
- {(char *)"wwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 383
- {(char *)"wwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2431
- {(char *)"wwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2943
- {(char *)"wwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3455
- {(char *)"wwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3967
- {(char *)"wwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 447
- {(char *)"wwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2495
- {(char *)"wwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3007
- {(char *)"wwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3519
- {(char *)"wwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4031
- {(char *)"www", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 511
- {(char *)"wwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2559
- {(char *)"wwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3071
- {(char *)"wwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3583
- {(char *)"wwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4095
+ {(char *)"xx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X')},
+ {(char *)"xxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X')},
+ {(char *)"xxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'X')},
+ {(char *)"xxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'Y')},
+ {(char *)"xxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'Z')},
+ {(char *)"xxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'W')},
+ {(char *)"xxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y')},
+ {(char *)"xxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'X')},
+ {(char *)"xxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'Y')},
+ {(char *)"xxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'Z')},
+ {(char *)"xxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'W')},
+ {(char *)"xxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z')},
+ {(char *)"xxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'X')},
+ {(char *)"xxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'Y')},
+ {(char *)"xxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'Z')},
+ {(char *)"xxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'W')},
+ {(char *)"xxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W')},
+ {(char *)"xxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'X')},
+ {(char *)"xxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'Y')},
+ {(char *)"xxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'Z')},
+ {(char *)"xxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'W')},
+ {(char *)"xy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y')},
+ {(char *)"xyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X')},
+ {(char *)"xyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'X')},
+ {(char *)"xyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'Y')},
+ {(char *)"xyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'Z')},
+ {(char *)"xyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'W')},
+ {(char *)"xyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y')},
+ {(char *)"xyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'X')},
+ {(char *)"xyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'Y')},
+ {(char *)"xyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'Z')},
+ {(char *)"xyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'W')},
+ {(char *)"xyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'Z')},
+ {(char *)"xyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'X')},
+ {(char *)"xyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'Y')},
+ {(char *)"xyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'Z')},
+ {(char *)"xyzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'Z', 'W')},
+ {(char *)"xyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'W')},
+ {(char *)"xywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'X')},
+ {(char *)"xywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'Y')},
+ {(char *)"xywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'W', 'Z')},
+ {(char *)"xyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'W')},
+ {(char *)"xz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z')},
+ {(char *)"xzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X')},
+ {(char *)"xzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'X')},
+ {(char *)"xzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'Y')},
+ {(char *)"xzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'Z')},
+ {(char *)"xzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'W')},
+ {(char *)"xzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'Y')},
+ {(char *)"xzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'X')},
+ {(char *)"xzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'Y')},
+ {(char *)"xzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'Z')},
+ {(char *)"xzyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'Y', 'W')},
+ {(char *)"xzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z')},
+ {(char *)"xzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'X')},
+ {(char *)"xzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'Y')},
+ {(char *)"xzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'Z')},
+ {(char *)"xzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'W')},
+ {(char *)"xzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'W')},
+ {(char *)"xzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'X')},
+ {(char *)"xzwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'W', 'Y')},
+ {(char *)"xzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'Z')},
+ {(char *)"xzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'W')},
+ {(char *)"xw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W')},
+ {(char *)"xwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X')},
+ {(char *)"xwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'X')},
+ {(char *)"xwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'Y')},
+ {(char *)"xwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'Z')},
+ {(char *)"xwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'W')},
+ {(char *)"xwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Y')},
+ {(char *)"xwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'X')},
+ {(char *)"xwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'Y')},
+ {(char *)"xwyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Y', 'Z')},
+ {(char *)"xwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'W')},
+ {(char *)"xwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Z')},
+ {(char *)"xwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'X')},
+ {(char *)"xwzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Z', 'Y')},
+ {(char *)"xwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'Z')},
+ {(char *)"xwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'W')},
+ {(char *)"xww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W')},
+ {(char *)"xwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'X')},
+ {(char *)"xwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'Y')},
+ {(char *)"xwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'Z')},
+ {(char *)"xwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'W')},
+ {(char *)"yx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X')},
+ {(char *)"yxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X')},
+ {(char *)"yxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'X')},
+ {(char *)"yxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'Y')},
+ {(char *)"yxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'Z')},
+ {(char *)"yxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'W')},
+ {(char *)"yxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y')},
+ {(char *)"yxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'X')},
+ {(char *)"yxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'Y')},
+ {(char *)"yxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'Z')},
+ {(char *)"yxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'W')},
+ {(char *)"yxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'Z')},
+ {(char *)"yxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'X')},
+ {(char *)"yxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'Y')},
+ {(char *)"yxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'Z')},
+ {(char *)"yxzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'Z', 'W')},
+ {(char *)"yxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'W')},
+ {(char *)"yxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'X')},
+ {(char *)"yxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'Y')},
+ {(char *)"yxwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'W', 'Z')},
+ {(char *)"yxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'W')},
+ {(char *)"yy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y')},
+ {(char *)"yyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X')},
+ {(char *)"yyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'X')},
+ {(char *)"yyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'Y')},
+ {(char *)"yyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'Z')},
+ {(char *)"yyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'W')},
+ {(char *)"yyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y')},
+ {(char *)"yyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'X')},
+ {(char *)"yyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'Y')},
+ {(char *)"yyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'Z')},
+ {(char *)"yyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'W')},
+ {(char *)"yyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z')},
+ {(char *)"yyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'X')},
+ {(char *)"yyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'Y')},
+ {(char *)"yyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'Z')},
+ {(char *)"yyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'W')},
+ {(char *)"yyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W')},
+ {(char *)"yywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'X')},
+ {(char *)"yywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'Y')},
+ {(char *)"yywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'Z')},
+ {(char *)"yyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'W')},
+ {(char *)"yz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z')},
+ {(char *)"yzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'X')},
+ {(char *)"yzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'X')},
+ {(char *)"yzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'Y')},
+ {(char *)"yzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'Z')},
+ {(char *)"yzxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'X', 'W')},
+ {(char *)"yzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y')},
+ {(char *)"yzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'X')},
+ {(char *)"yzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'Y')},
+ {(char *)"yzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'Z')},
+ {(char *)"yzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'W')},
+ {(char *)"yzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z')},
+ {(char *)"yzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'X')},
+ {(char *)"yzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'Y')},
+ {(char *)"yzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'Z')},
+ {(char *)"yzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'W')},
+ {(char *)"yzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'W')},
+ {(char *)"yzwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'W', 'X')},
+ {(char *)"yzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'Y')},
+ {(char *)"yzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'Z')},
+ {(char *)"yzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'W')},
+ {(char *)"yw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W')},
+ {(char *)"ywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'X')},
+ {(char *)"ywxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'X')},
+ {(char *)"ywxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'Y')},
+ {(char *)"ywxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'X', 'Z')},
+ {(char *)"ywxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'W')},
+ {(char *)"ywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y')},
+ {(char *)"ywyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'X')},
+ {(char *)"ywyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'Y')},
+ {(char *)"ywyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'Z')},
+ {(char *)"ywyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'W')},
+ {(char *)"ywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'Z')},
+ {(char *)"ywzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'Z', 'X')},
+ {(char *)"ywzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'Y')},
+ {(char *)"ywzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'Z')},
+ {(char *)"ywzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'W')},
+ {(char *)"yww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W')},
+ {(char *)"ywwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'X')},
+ {(char *)"ywwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'Y')},
+ {(char *)"ywwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'Z')},
+ {(char *)"ywww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'W')},
+ {(char *)"zx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X')},
+ {(char *)"zxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X')},
+ {(char *)"zxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'X')},
+ {(char *)"zxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'Y')},
+ {(char *)"zxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'Z')},
+ {(char *)"zxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'W')},
+ {(char *)"zxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'Y')},
+ {(char *)"zxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'X')},
+ {(char *)"zxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'Y')},
+ {(char *)"zxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'Z')},
+ {(char *)"zxyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'Y', 'W')},
+ {(char *)"zxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z')},
+ {(char *)"zxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'X')},
+ {(char *)"zxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'Y')},
+ {(char *)"zxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'Z')},
+ {(char *)"zxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'W')},
+ {(char *)"zxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'W')},
+ {(char *)"zxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'X')},
+ {(char *)"zxwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'W', 'Y')},
+ {(char *)"zxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'Z')},
+ {(char *)"zxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'W')},
+ {(char *)"zy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y')},
+ {(char *)"zyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'X')},
+ {(char *)"zyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'X')},
+ {(char *)"zyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'Y')},
+ {(char *)"zyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'Z')},
+ {(char *)"zyxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'X', 'W')},
+ {(char *)"zyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y')},
+ {(char *)"zyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'X')},
+ {(char *)"zyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'Y')},
+ {(char *)"zyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'Z')},
+ {(char *)"zyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'W')},
+ {(char *)"zyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z')},
+ {(char *)"zyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'X')},
+ {(char *)"zyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'Y')},
+ {(char *)"zyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'Z')},
+ {(char *)"zyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'W')},
+ {(char *)"zyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'W')},
+ {(char *)"zywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'W', 'X')},
+ {(char *)"zywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'Y')},
+ {(char *)"zywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'Z')},
+ {(char *)"zyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'W')},
+ {(char *)"zz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z')},
+ {(char *)"zzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X')},
+ {(char *)"zzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'X')},
+ {(char *)"zzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'Y')},
+ {(char *)"zzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'Z')},
+ {(char *)"zzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'W')},
+ {(char *)"zzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y')},
+ {(char *)"zzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'X')},
+ {(char *)"zzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'Y')},
+ {(char *)"zzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'Z')},
+ {(char *)"zzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'W')},
+ {(char *)"zzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z')},
+ {(char *)"zzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'X')},
+ {(char *)"zzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'Y')},
+ {(char *)"zzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'Z')},
+ {(char *)"zzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'W')},
+ {(char *)"zzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W')},
+ {(char *)"zzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'X')},
+ {(char *)"zzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'Y')},
+ {(char *)"zzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'Z')},
+ {(char *)"zzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'W')},
+ {(char *)"zw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W')},
+ {(char *)"zwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'X')},
+ {(char *)"zwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'X')},
+ {(char *)"zwxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'X', 'Y')},
+ {(char *)"zwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'Z')},
+ {(char *)"zwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'W')},
+ {(char *)"zwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'Y')},
+ {(char *)"zwyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'Y', 'X')},
+ {(char *)"zwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'Y')},
+ {(char *)"zwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'Z')},
+ {(char *)"zwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'W')},
+ {(char *)"zwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z')},
+ {(char *)"zwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'X')},
+ {(char *)"zwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'Y')},
+ {(char *)"zwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'Z')},
+ {(char *)"zwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'W')},
+ {(char *)"zww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W')},
+ {(char *)"zwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'X')},
+ {(char *)"zwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'Y')},
+ {(char *)"zwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'Z')},
+ {(char *)"zwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'W')},
+ {(char *)"wx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X')},
+ {(char *)"wxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X')},
+ {(char *)"wxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'X')},
+ {(char *)"wxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'Y')},
+ {(char *)"wxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'Z')},
+ {(char *)"wxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'W')},
+ {(char *)"wxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Y')},
+ {(char *)"wxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'X')},
+ {(char *)"wxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'Y')},
+ {(char *)"wxyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Y', 'Z')},
+ {(char *)"wxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'W')},
+ {(char *)"wxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Z')},
+ {(char *)"wxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'X')},
+ {(char *)"wxzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Z', 'Y')},
+ {(char *)"wxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'Z')},
+ {(char *)"wxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'W')},
+ {(char *)"wxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W')},
+ {(char *)"wxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'X')},
+ {(char *)"wxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'Y')},
+ {(char *)"wxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'Z')},
+ {(char *)"wxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'W')},
+ {(char *)"wy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y')},
+ {(char *)"wyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'X')},
+ {(char *)"wyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'X')},
+ {(char *)"wyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'Y')},
+ {(char *)"wyxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'X', 'Z')},
+ {(char *)"wyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'W')},
+ {(char *)"wyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y')},
+ {(char *)"wyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'X')},
+ {(char *)"wyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'Y')},
+ {(char *)"wyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'Z')},
+ {(char *)"wyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'W')},
+ {(char *)"wyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'Z')},
+ {(char *)"wyzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'Z', 'X')},
+ {(char *)"wyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'Y')},
+ {(char *)"wyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'Z')},
+ {(char *)"wyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'W')},
+ {(char *)"wyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W')},
+ {(char *)"wywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'X')},
+ {(char *)"wywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'Y')},
+ {(char *)"wywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'Z')},
+ {(char *)"wyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'W')},
+ {(char *)"wz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z')},
+ {(char *)"wzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'X')},
+ {(char *)"wzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'X')},
+ {(char *)"wzxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'X', 'Y')},
+ {(char *)"wzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'Z')},
+ {(char *)"wzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'W')},
+ {(char *)"wzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'Y')},
+ {(char *)"wzyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'Y', 'X')},
+ {(char *)"wzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'Y')},
+ {(char *)"wzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'Z')},
+ {(char *)"wzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'W')},
+ {(char *)"wzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z')},
+ {(char *)"wzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'X')},
+ {(char *)"wzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'Y')},
+ {(char *)"wzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'Z')},
+ {(char *)"wzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'W')},
+ {(char *)"wzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W')},
+ {(char *)"wzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'X')},
+ {(char *)"wzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'Y')},
+ {(char *)"wzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'Z')},
+ {(char *)"wzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'W')},
+ {(char *)"ww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W')},
+ {(char *)"wwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X')},
+ {(char *)"wwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'X')},
+ {(char *)"wwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'Y')},
+ {(char *)"wwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'Z')},
+ {(char *)"wwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'W')},
+ {(char *)"wwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y')},
+ {(char *)"wwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'X')},
+ {(char *)"wwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'Y')},
+ {(char *)"wwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'Z')},
+ {(char *)"wwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'W')},
+ {(char *)"wwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z')},
+ {(char *)"wwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'X')},
+ {(char *)"wwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'Y')},
+ {(char *)"wwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'Z')},
+ {(char *)"wwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'W')},
+ {(char *)"www", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W')},
+ {(char *)"wwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'X')},
+ {(char *)"wwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'Y')},
+ {(char *)"wwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'Z')},
+ {(char *)"wwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'W')},
+
+#undef AXIS_FROM_CHAR
+#undef SWIZZLE
+#undef _VA_SWIZZLE_1
+#undef _VA_SWIZZLE_2
+#undef _VA_SWIZZLE_3
+#undef _VA_SWIZZLE_4
+
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-/* Python script used to make swizzle array */
-/*
-SWIZZLE_BITS_PER_AXIS = 3
-SWIZZLE_VALID_AXIS = 0x4
-
-axis_dict = {}
-axis_pos = {'x':0, 'y':1, 'z':2, 'w':3}
-axises = 'xyzw'
-while len(axises) >= 2:
-
- for axis_0 in axises:
- axis_0_pos = axis_pos[axis_0]
- for axis_1 in axises:
- axis_1_pos = axis_pos[axis_1]
- axis_dict[axis_0 + axis_1] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS))' % (axis_0_pos, axis_1_pos)
- if len(axises)>2:
- for axis_2 in axises:
- axis_2_pos = axis_pos[axis_2]
- axis_dict[axis_0 + axis_1 + axis_2] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS * 2)))' % (axis_0_pos, axis_1_pos, axis_2_pos)
- if len(axises)>3:
- for axis_3 in axises:
- axis_3_pos = axis_pos[axis_3]
- axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((%s|SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((%s|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS * 3))) ' % (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos)
-
- axises = axises[:-1]
-
-
-items = axis_dict.items()
-items.sort(key = lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3'))
-
-unique = set()
-for key, val in items:
- num = eval(val)
- set_str = 'Vector_setSwizzle' if (len(set(key)) == len(key)) else 'NULL'
- print '\t{"%s", %s(getter)Vector_getSwizzle, (setter)%s, NULL, SET_INT_IN_POINTER(%s)}, // %s' % (key, (' '*(4 - len(key))), set_str, axis_dict[key], num)
- unique.add(num)
-
-if len(unique) != len(items):
- print "ERROR"
-*/
+/**
+ * Python script used to make swizzle array:
+ *
+ * \code{.py}
+ * SWIZZLE_BITS_PER_AXIS = 3
+ * SWIZZLE_VALID_AXIS = 0x4
+ *
+ * axis_dict = {}
+ * axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3}
+ * axises = 'xyzw'
+ * while len(axises) >= 2:
+ * for axis_0 in axises:
+ * axis_0_pos = axis_pos[axis_0]
+ * for axis_1 in axises:
+ * axis_1_pos = axis_pos[axis_1]
+ * axis_dict[axis_0 + axis_1] = (
+ * '((%s | SWIZZLE_VALID_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' %
+ * (axis_0_pos, axis_1_pos))
+ * if len(axises) > 2:
+ * for axis_2 in axises:
+ * axis_2_pos = axis_pos[axis_2]
+ * axis_dict[axis_0 + axis_1 + axis_2] = (
+ * '((%s | SWIZZLE_VALID_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' %
+ * (axis_0_pos, axis_1_pos, axis_2_pos))
+ * if len(axises) > 3:
+ * for axis_3 in axises:
+ * axis_3_pos = axis_pos[axis_3]
+ * axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = (
+ * '((%s | SWIZZLE_VALID_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) ' %
+ * (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos))
+ *
+ * axises = axises[:-1]
+ *
+ *
+ * items = list(axis_dict.items())
+ * items.sort(key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3'))
+ *
+ * unique = set()
+ * for key, val in items:
+ * num = eval(val)
+ * set_str = 'Vector_swizzle_set' if (len(set(key)) == len(key)) else 'NULL'
+ * key_args = ', '.join(["'%s'" % c for c in key.upper()])
+ * print('\t{(char *)"%s", %s(getter)Vector_swizzle_get, (setter)%s, NULL, SWIZZLE(%s)},' %
+ * (key, (' ' * (4 - len(key))), set_str, key_args))
+ * unique.add(num)
+ *
+ * if len(unique) != len(items):
+ * print("ERROR, duplicate values found")
+ * \endcode
+ */
/* ROW VECTOR Multiplication - Vector X Matrix
* [x][y][z] * [1][4][7]
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index 39f62f9fc33..509ad6f3515 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -238,6 +238,9 @@ void RE_render_result_rect_from_ibuf(
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname);
+/* add passes for grease pencil */
+struct RenderPass *RE_create_gp_pass(struct RenderResult *rr, const char *layername, const char *viewname);
+
/* obligatory initialize call, disprect is optional */
void RE_InitState(struct Render *re, struct Render *source, struct RenderData *rd,
struct SceneRenderLayer *srl,
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h
index 2619ac76d59..0c4f4e20325 100644
--- a/source/blender/render/intern/include/render_result.h
+++ b/source/blender/render/intern/include/render_result.h
@@ -83,6 +83,9 @@ void render_result_save_empty_result_tiles(struct Render *re);
void render_result_exr_file_begin(struct Render *re);
void render_result_exr_file_end(struct Render *re);
+/* render pass wrapper for gpencil */
+struct RenderPass *gp_add_pass(struct RenderResult *rr, struct RenderLayer *rl, int channels, int passtype, const char *viewname);
+
void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart, const char *viewname);
void render_result_exr_file_path(struct Scene *scene, const char *layname, int sample, char *filepath);
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
index 02a49fc3c8f..724a809077e 100644
--- a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
@@ -42,6 +42,10 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#if __cplusplus >= 201103L
+using std::isfinite;
+#endif
+
static bool selected_node(RTBuilder::Object *node)
{
return node->selected;
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 1ee905c596c..ec629aa2863 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -2785,6 +2785,7 @@ static void do_render_all_options(Render *re)
/* ensure no images are in memory from previous animated sequences */
BKE_image_all_free_anim_ibufs(re->r.cfra);
+ BKE_sequencer_all_free_anim_ibufs(re->r.cfra);
if (RE_engine_render(re, 1)) {
/* in this case external render overrides all */
@@ -4018,3 +4019,31 @@ RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const c
}
return rp;
}
+
+/* create a renderlayer and renderpass for grease pencil layer */
+RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const char *viewname)
+{
+ RenderLayer *rl = BLI_findstring(&rr->layers, layername, offsetof(RenderLayer, name));
+ /* only create render layer if not exist */
+ if (!rl) {
+ rl = MEM_callocN(sizeof(RenderLayer), layername);
+ BLI_addtail(&rr->layers, rl);
+ BLI_strncpy(rl->name, layername, sizeof(rl->name));
+ rl->lay = 0;
+ rl->layflag = SCE_LAY_SOLID;
+ rl->passflag = SCE_PASS_COMBINED;
+ rl->rectx = rr->rectx;
+ rl->recty = rr->recty;
+ }
+
+ /* clear previous pass if exist or the new image will be over previous one*/
+ RenderPass *rp = RE_pass_find_by_type(rl, SCE_PASS_COMBINED, viewname);
+ if (rp) {
+ if (rp->rect) {
+ MEM_freeN(rp->rect);
+ }
+ BLI_freelinkN(&rl->passes, rp);
+ }
+ /* create a totally new pass */
+ return gp_add_pass(rr, rl, 4, SCE_PASS_COMBINED, viewname);
+}
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index bddd84c45d7..6ea46af6f7e 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -540,6 +540,11 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int
return rpass;
}
+/* wrapper called from render_opengl */
+RenderPass *gp_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname)
+{
+ return render_layer_add_pass(rr, rl, channels, passtype, viewname);
+}
#ifdef WITH_CYCLES_DEBUG
const char *RE_debug_pass_name_get(int debug_type)
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 26a1c7038d8..69905fc296b 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -387,9 +387,7 @@ void WM_gestures_remove(struct bContext *C);
/* fileselecting support */
void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op);
void WM_event_fileselect_event(struct wmWindowManager *wm, void *ophandle, int eventval);
-#ifndef NDEBUG
void WM_event_print(const struct wmEvent *event);
-#endif
void WM_operator_region_active_win_set(struct bContext *C);
@@ -443,6 +441,7 @@ enum {
WM_JOB_TYPE_SEQ_BUILD_PREVIEW,
WM_JOB_TYPE_POINTCACHE,
WM_JOB_TYPE_DPAINT_BAKE,
+ WM_JOB_TYPE_ALEMBIC,
/* add as needed, screencast, seq proxy build
* if having hard coded values is a problem */
};
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 962ed3c040d..3825db14e93 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -862,11 +862,8 @@ static int wm_automatic_draw_method(wmWindow *win)
* copy to texture is slow though and so we use overlap instead there. */
if (win->drawmethod == USER_DRAW_AUTOMATIC) {
- /* ATI opensource driver is known to be very slow at this */
- if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE))
- return USER_DRAW_OVERLAP;
/* Windows software driver darkens color on each redraw */
- else if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE))
+ if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE))
return USER_DRAW_OVERLAP_FLIP;
else if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_UNIX, GPU_DRIVER_SOFTWARE))
return USER_DRAW_OVERLAP;
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 4515ae92f66..01dc77127d2 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -81,9 +81,7 @@
#include "wm_event_system.h"
#include "wm_event_types.h"
-#ifndef NDEBUG
-# include "RNA_enum_types.h"
-#endif
+#include "RNA_enum_types.h"
static void wm_notifier_clear(wmNotifier *note);
static void update_tablet_data(wmWindow *win, wmEvent *event);
@@ -550,8 +548,6 @@ void WM_operator_region_active_win_set(bContext *C)
}
/* for debugging only, getting inspecting events manually is tedious */
-#ifndef NDEBUG
-
void WM_event_print(const wmEvent *event)
{
if (event) {
@@ -593,8 +589,6 @@ void WM_event_print(const wmEvent *event)
}
}
-#endif /* NDEBUG */
-
/**
* Show the report in the info header.
*/
@@ -1969,15 +1963,11 @@ static int wm_action_not_handled(int action)
static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers)
{
-#ifndef NDEBUG
const bool do_debug_handler = (G.debug & G_DEBUG_HANDLERS) &&
/* comment this out to flood the console! (if you really want to test) */
!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)
;
-# define PRINT if (do_debug_handler) printf
-#else
-# define PRINT(format, ...)
-#endif
+# define PRINT if (do_debug_handler) printf
wmWindowManager *wm = CTX_wm_manager(C);
wmEventHandler *handler, *nexthandler;
@@ -2382,20 +2372,16 @@ void wm_event_do_handlers(bContext *C)
while ( (event = win->queue.first) ) {
int action = WM_HANDLER_CONTINUE;
-#ifndef NDEBUG
if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
printf("\n%s: Handling event\n", __func__);
WM_event_print(event);
}
-#endif
/* take care of pie event filter */
if (wm_event_pie_filter(win, event)) {
-#ifndef NDEBUG
if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
printf("\n%s: event filtered due to pie button pressed\n", __func__);
}
-#endif
BLI_remlink(&win->queue, event);
wm_event_free(event);
continue;
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index e2ccb6fbbd7..3405537a09c 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -577,7 +577,7 @@ static void lib_relocate_do(
WMLinkAppendDataItem *item;
/* We remove it from current Main, and add it to items to link... */
- /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitely linked here... */
+ /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */
BLI_remlink(lbarray[lba_idx], id);
item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id);
BLI_BITMAP_SET_ALL(item->libraries, true, lapp_data->num_libraries);
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index 7ec2aea73e1..18836f34c99 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -97,6 +97,8 @@ void WM_operator_properties_filesel(
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "filter_collada", (filter & FILE_TYPE_COLLADA) != 0, "Filter COLLADA files", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_alembic", (filter & FILE_TYPE_ALEMBIC) != 0, "Filter Alembic files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "filter_folder", (filter & FILE_TYPE_FOLDER) != 0, "Filter folders", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "filter_blenlib", (filter & FILE_TYPE_BLENDERLIB) != 0, "Filter Blender IDs", "");
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 42f6585f152..425287993d9 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -69,6 +69,8 @@
#include "ED_screen.h"
#include "ED_fileselect.h"
+#include "UI_interface.h"
+
#include "PIL_time.h"
#include "GPU_draw.h"
@@ -1194,14 +1196,27 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
break;
}
case GHOST_kEventNativeResolutionChange:
+ {
// printf("change, pixel size %f\n", GHOST_GetNativePixelSize(win->ghostwin));
U.pixelsize = wm_window_pixelsize(win);
BKE_blender_userdef_refresh();
+
+ // close all popups since they are positioned with the pixel
+ // size baked in and it's difficult to correct them
+ wmWindow *oldWindow = CTX_wm_window(C);
+ CTX_wm_window_set(C, win);
+ UI_popup_handlers_remove_all(C, &win->modalhandlers);
+ CTX_wm_window_set(C, oldWindow);
+
+ wm_window_make_drawable(wm, win);
+ wm_draw_window_clear(win);
+
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
break;
+ }
case GHOST_kEventTrackpad:
{
GHOST_TEventTrackpadData *pd = data;